去年年底换了工作,在经过两个月的调整期后,工作量开始逐渐上来了,特别是四月份的前两周,简直有种疲于奔命的感觉。还好,现在已经逐步适应了新公司的节奏
三月中旬,终于把房子签了,一下变成了一贫如洗且负债累累的房奴。但却并没有给我带来压力山大的感觉~~~~或许正应了这个词:死猪不怕开水烫。。。哈哈
╮(╯▽╰)╭,不多想了,睡觉~~~~
这周碰到了两个不靠谱的东西,一个是微信自动回复里的图片,另一个是魅族手机
微信的公众平台API却是非常强大,可以依托它做出各种精彩的应用,然而,这周一却碰到了一个美中不足的问题不,这个问题不大不小却让人很不爽:自动回复里的图片,不管你给什么尺寸,在不同的设备里,总是会或左右,或上下的被截去一段,比如下图公众号“IT程序猿”发的内容:
可以看到,中间的图片,左侧二维码只显示了一般,右侧文字也没遮住了一部分
我测试了各种尺寸的图片,发现都不可以,最后的解决方案是:用大约1:2的图片,但是图片的上下、左右都不放重要内容,这样就随它截去了~~
这周碰上的另一个东西是魅族手机的系统浏览器。
魅族版的android,界面确实很漂亮,甚至可以说很华丽,但它的自带浏览器,确实也很屎。
昨天测试发现一个bug,在这个浏览器内,页面里里面有几个输入框,当输入时,整个页面都会随着上下不停的抖动。貌似,是因为有输入动作时,浏览器会试图将输入框放到页面的顶端,但每次定位都不成功,下次又试图再次定位,于是就出现了这种怪异的现象~~解决方案是。。。目前还没有
用了近三个月时间,终于“读完”了阿西莫夫的基地系列~~~
据说上图是读客版基地的封面,里面的四个“经典”人物都深受基地的影响,可是我买到的读客版却没有这个封面
已经很久没有读过长篇了,平时上班不读书,晚上、周末不读书,这次重读基地系列,完全是利用每天坐地铁的时间。每天大约一个小时,能读三、四十页
前面说“读完”,其实只读了5本,中间“略过”4、5两部讲谢顿生平的“基地前传”,,本来想读完第七部在读前面两部,可是后来就没有兴趣了。。。太长了
大学时读过基地的第1、2部,印象深刻,所以今年年初才会心血来潮买了七部曲全集来看~~但是,说实话,后面几部真的有些失望
(以下有剧透。渗入)
前三部据说是作者年轻时写的,真的是“史诗”级的作品,每一步包含若干个故事,每一个故事结构紧凑,人物鲜明,所有故事一起构成了“第一基地”前300年的发展历程,同时也逐渐揭开了“第二基地”的神秘面纱。
后面几部,则是作者年长以后写的,或许是所谓“写作手法”的成熟,故事变得冗长起来,后面两部的总篇幅和前三步不相上下,讲的却只是一个故事,人物就只有可数的几个。而且,情节也上否定了前三部奉为神明的“谢顿计划”,转向了作者的另一个套大作:机器人系列。特别是最后一部“基地与地球”,四百多页的篇幅,有三分一都是在讨论“盖亚星系”的种种优点,整篇都是在“寻找地球”,可是最后找到了地球,给出的选择“盖亚星系”的理由,在我看来却是严重的牵强附会,更加不明白为什么会选择“盖亚星系”作为银河的未来发展方向
不过,整体来讲,基地系列还是很棒的一套书,有时间的朋友可以拿来读读
久闻php ci的大名,一直没有机会使用,上周做个小项目,用到了这个框架,整体感觉很不错,这里跟大家分享一下ci的快速入门
ci文档入口:http://codeigniter.org.cn/user_guide/toc.html(中文!)
ci,即codeigniter,我用的版本是当前的最新版本2.1.3
使用ci,只要将apache或者nginx的发布目录指到codeigniter的顶级目录下就可以
下面,就按MVC的顺序来所说ci的使用
url
比如要访问/news/list的action,默认情况下,url需要这么来写:xxx.xxx.xxx/index.php/news/list~~多个index.php,很别扭
如果要去掉这个index.php,需要加上“.htaccess”来实现urlRewrite:
1 2 3 | RewriteEngine on RewriteCond $1 !^(index\.php|images|robots\.txt) RewriteRule ^(.*)$ /index.php/$1 [L] |
C
ci的controller位于application/controllers目录下,文件名和ation方法名需要遵循规约变成的规则
不多说了,还是直接写代码吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class News extends CI_Controller{ function __construct(){ parent::__construct(); } // http://localhost/news/lists,如果要使用其他的url,需要到“application/config/routes.php”去配置路由 public function lists($keyWords){ //使用model,model()方法的第一个参数“news”对应application/models/news.php //第二个参数“News”对应下面如何引用这个model:$this->News,如果不设置这个参数,这是$this->news,及model的名字 $this->load->model('news', 'News'); $data['list1'] = $this->News->list_all(); //使用library核心类 $this->load->library('news_manager'); $data['list2'] = $this->news_manager->search_news($keyWords); //使用view,向浏览器输出内容 $this->load->view('header'); $this->load->view('news/list', $data); $this->load->view('footer'); } // public function view_news($id){ $this->load->view('view_news', array( 'title' => news->title, 'content' => $news->content )); } } |
如果要加载非默认数据源,需要到config/database.php里配置不同的数据源,比如现在除了default,又添加了一个叫做abc的数据源,我们如何调用哪个它哪?
1 2 3 4 5 6 7 8 9 | //abc $abc = $this->load->database('abc', true); $this->load->model('abc_table1'); $thisi->abc_table1->db = $abc; //default $defaultdb = $this->load->database('default', true); $this->load->model('news'); $this->news->db = $defaultdb; //即通过“$this->load->database”建立数据源,然后通过$thisi->model->db=xxx为当前某个model的引用设置数据源 |
另一个要说的功能是:可以将controller文件放在子文件夹中,比如“application/controllers/shop/products.php”,调用它就需要“/index.php/shop/products/xxx”
M
上面的代码已经用到了模型的调用,这里所说模型的常用方法
增
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class news extends CI_Model{ function __construct(){ parent::__construct(); } function cretae($title, $content){ $data = array( 'title' => $title, 'content' => $content, 'create_time' => new time() ); //INSERT INTO news (title, content, create_time) VALUES ('xxxx', 'xxxx', 'xxxx') $this->db->insert('news', $data); } } |
删
1 2 3 4 5 | //DELETE FROM mytable WHERE id = $id $this->db->delete('news', array('id' => $id)); //等效 $this->db->where('id', $id); $this->db->delete('news'); |
改
1 2 3 4 5 6 7 | $data = array( 'title' => $title, 'content' => $content, ); $this->db->where('id', $id); //UPDATE news SET title = xxxx, content = xxx where id = $id $this->db->update('news', $data); |
查
1 2 3 4 5 6 7 8 9 | //SELECT * FROM news $query = $this->db->get('news'); //select * from news where id = $id limit $offset, $limit $query = $this->db->get_where('news', array('id' => $id), $limit, $offset); //直接取结果集 $list = $query->result(); //取结果集的数量 $count = $query->num_rows(); //此外,ci的查询还有丰富的方法,支持各种查询,诸如:where/or_where/where_in/or_where_in/like等等 |
打印sql
1 | echo $this->db->last_query(); |
V
ci的view位于application/views/目录下,比如view_news.php,可以直接使用php代码书写
1 2 3 4 5 6 7 8 | <html> <head> <title><?php echo $title;?></title> </head> <body> <h1><?php echo $content;?></h1> </body> </html> |
上面的title、content参数,可以通过下面的方式在controller中传递过来:
1 2 3 4 | $this->load->view('view_news', array( 'title' => $news->title, 'content' => $news->content )); |
———
参考:http://codeigniter.org.cn/user_guide/toc.html

———
蒋评:
先不论框架的易用性、性能等因素,相对于cakephp和thinkphp,ci最大的又是就是它的中文资料丰富,有完整的中文文档,甚至官网还提供中文视频教程:http://codeigniter.org.cn/tutorials,这些都大大降低了新手的入门难度[赞]
jquery框架的神奇之处在于,即便是对于我这种以“精通jquery”自居的人(嘿嘿),每次在看文档时,仍然能有新的发现,比如今天,就发现$(xxx)方法,其实还可以有第二个参数,并且随着第一个参数的不同,第二个参数还有不同的含义:
1. $(selector, [context])
这种用法,相当于 $(context).find(selector) 或者 context.find(selector)
2. jQuery(html, [ownerDocument])
文档对ownerDocument的解释是:“创建DOM元素所在的文档”
也就是说,如果你要编写挎document的脚本,比如iframe或者用window.open开一个新窗口,可能会用得着它
3. jQuery(html, props)
这个比较简单,直接把文档里的例子贴出来了:
$("<input>", {
type: "text",
val: "Test",
focusin: function() {
$(this).addClass("active");
},
focusout: function() {
$(this).removeClass("active");
}
}).appendTo("form")
也就是说,props内的属性会像.attr()方法一样,被设置到新创建的标签内
注:IE总不能通过.attr()设置input的type属性
----------
参考:http://www.w3school.com.cn/jquery/core_jquery.asp#syntax1
1. WebKit是什么?
WebKit是一个开源的Web浏览器引擎。
WebKit的HTML解析器和JavaScript解析器代码分别源自KDE的KHTML和KJS代码库。
2. 谁在使用WebKit?
“MacOS X系统的Safari、Dashboard、Mail和很多其他OS X程序”
这就是在说,WebKit是Safari背后的浏览器引擎。还需要补充的是,Apple在Safari里面使用了自己的Nitro JavaScript引擎(只用WebKit来渲染HTML)。
Google官方说明:Chromium使用WebKit做为渲染引擎。与其打造Chromium特有的实现方式,我们更希望去尽可能多的去为使用WebKit核心的浏览器做贡献。
这是说Chrome也在使用Nitro JS引擎?不,Chrome有他自己的V8 JavaScript引擎。简单的说,Chrome也使用WebKit,但是它也实现了自己的JavaScript处理方式。V8同时还是驱动Node.js的JavaScript引擎。
Opera会使用Chromium实现的WebKit,也会使用V8引擎。这就是说虽然Opera在宣称自己使用WebKit,但事实上它使用WebKit和Safari与其他浏览器使用的WebKit并不完全一样。如果你想客观了解现状,这是必须清楚的概念。
3. 现在WebKit究竟有多少分支?
所以我们知道现在WebKit正在驱动,或者将会驱动3个主流浏览器。但是WebKit还有多少其他类型的实现?
确实还有很多很多WebKit的变种,特别是在移动领域。他们都是WebKit的分支。
4. 这些WebKit的分支有多少差别?
有一种假设:因为这些浏览器都在使用WebKit,所以他们也会以同样的方式去支持相同的特性。
对于很多基本的特性来说,确实是这样。但是对于很多小众特性,就未必如此了。
举例来说,当Chrome开始支持游戏手柄API的时候,Safari不但还没开始支持,而且以后也不太可能支持。另一个例子是WebGL。做为在Chrome已经支持了很久的特性之一,Safari却才刚刚看到了曙光(而且还是在开发者选项里)。当然,这些还都是比较出名的例子。还有很多试验性的例子潜伏在大众的视野之下。
甚至很多基础的、日常的功能,在不同的代码分支下都有所不同。PPK完整的总结了这些WebKit的差异。
5. WebKit的逐步普及,对web开发有什么影响?
如果一个浏览器迁移到了WebKit,那是不是意味着(在编写代码的时候)可以少测试一个浏览器了?
不。每个浏览器都有它自己的怪异模式、性能差异、设计,和功能。所以每个浏览器都要测试。
当一个功能加入到WebKit的时候,是不是意味着在其他浏览器里就可以使用这功能了?
当然不是。比如游戏手柄API的例子。Paul Irish强调了这样一个事实:WebKit浏览器们可以挑选究竟把哪些API放入他们的版本。比如Chrome选择支持游戏手柄API。很多API在WebKit的层面就已经被实现了,但是WebKit项目书允许关闭这些功能。(编者注:Paul Irish是Google Chrome的员工,他曾在jQuery团队工作两年。)
如果所有的浏览器都使用相同的引擎,这对程序员来说意味着什么?
随着时间的流逝,他们会意识到尽管同是WebKit,也会有很多不同的东西。
6. 新特性如何加入到WebKit中,谁又来负责审核?
现在有许多公司正在为WebKit项目贡献自己的力量。
WebKit项目提交和审查页面提到只能有老的代码提交员和审核员才能提名新的新的代码提交员与审核员。这比较合理。然而,无论WebKit项目决定让谁参与进来,最终都还是要让Apple来做审核:
当有人被WebKit代码提交员成功提名后,Apple会处理发送代码提交员协议,在签署协议之后,Apple会继续开通SVN账户。
对于这一点并没有什么隐秘的动机,但这确实在告诉大家,WebKit和很多开源项目一样,并不是真正分散和民主的。权利是且必须是集中的——只有这样才能保证能做出决定,并且把事情做成。
7. 如何评价WebKit?
允许我们强调一下,WebKit是好的。它有开放的流程和强大的贡献者。我们只是想澄清一个当下被广泛接受的错误概念——一个WebKit等于所有WebKit,还有——如果所有浏览器都选择WebKit,那么对开发者来说,工作会变得更轻松。
我的意思是说,与众多独立的浏览器引擎会为市场带来多样性一样,WebKit在这一点来说,同样会表现的很棒。
—————
转自:http://www.infoq.com/cn/news/2013/02/webkit-history-and-now
前几天刚发了一篇利用setTimeout提高ui响应速度的文章,本来感觉自己对setTimeout的理解已经够深入了,但是昨天偶然听说setTimeout其实是有“bug”的:在setTimeout 0时,并不能精确定时,还说IE会有16ms的延时
虽然早就想到js这种东西定时肯定不会很精确的,而且这个时延对“提高ui响应速度”影响也不大,但是如果是做动画的话,影响可能就比较大了,还说抽空写了段小程序试了试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //定时长度 var OUT_TIME = 0; //循环次数 var LOOP_COUNT = 100; $(function(){ $('a#start').click(function(){ var t1 = mst(); loopOut(LOOP_COUNT, t1); }); }); //递归循环 function loopOut(i, t1){ if(--i > 0){ setTimeout(function(){ loopOut(i, t1); }, OUT_TIME); }else{ var t2 = mst(); alert(t2 - t1); } } //返回当前时间点的毫秒数 function mst(){ return new Date().getTime(); } |
上面的程序,当点击“start”按钮后,首先会取当前时间t1,然后调用loopOut,当循环参数i大于0时,会通过setTimeout定时0ms递归调用loopOut,同时i会减1,形成循环终止条件,放循环满100次时,再次取当前时间,与t1相减,也就是100此setTimeout循环的用时
测试结果发现,“IE会有16ms的延时”,这话并不算错,IE7、8,最后的返回值大概是1530~1550,算起来,一次setTimeout大概要延迟DT=15.4ms
而且chrome/safari/firefox,返回值大概是420~430,即DT=4.2ms
当增大定时长度OUT_TIME时,只有增大到各浏览器的DT时,实际的定时长度才会有效,也就是DT可以看成“最小定时长度”
但是即便定时长度大于DT定时也是不精确的,非IE大概是0.2ms,IE就有点离谱了,比如OUT_TIME=50时,平均每次的定时长度大概是60ms,差了10ms(鄙视)
综上所述,虽然setTimeout传入的时间值是毫秒,但是是在并不精确,如果对精度要求较高,最好好好计算各浏览器的误差
下面讨论另外两种情况
1. 既然setTimeout有这种问题,那么与它类似的setInterval有问题吗?
将上面的“loopOut”方法稍加改进,即可setInterval:
1 2 3 4 5 6 7 8 9 | function loopOut(i, t1){ var si = setInterval(function(){ if(--i == OUT_TIME){ var t2 = mst(); alert(t2 - t1); clearInterval(si); } }, OUT_TIME); } |
这是,IE再次表型了它的卓尔不群:当OUT_TIME=0的时候,setInterval的回调方法只会执行一次,只有OUT_TIME>0,这段脚本在IE里才能正常执行
除此之外,setInterval和前面setTimeout的表现基本相同
2. node.js的setTimeout精确吗?
将上面click部分的代码去掉,稍加修改,既可以让代码再node里执行,但是为了去除代码初始化的影响,这里用了另外一个setTimeout,让其在程序初始化100ms以后在执行
1 2 3 4 | setTimeout(function(){ var t1 = mst(); loopOut(LOOP_COUNT, t1); }, 100); |
测试结果发现,服务器端脚本相对浏览器端的效率果然高出不少,在循环次数为100的时候,node.js的setTimeout 0ms的延迟大约在0.1ms左右,当把循环次数提高的100000后,平均的延迟降到了0.01ms
随着webApp的流行,前端应用越来越复杂,js脚本越来越多,为了提高页面页面响应速度,我们常常需要对js进行压缩、整合
但是经过压缩后的js,调试起来会特别麻烦,基本是对于chrome/ff这些“现代”浏览器,如果压缩过的js出了错误,报的错误也是让你无所适从
之前的做法是,在开发环境不回js做压缩、整合,而且在上线前最后确认的verify以及线上环境对js做压缩,这么做虽然可以避免上面的问题,但又是js的加载顺序对功能会有影响,所以还是不能完全模拟线上的情况
更何况,线上可能还会出问题的
这里介绍一种可以调试压缩脚本的方法,就是所谓“Source Map”,大概的原理是这样的:
在使用compiler.jar压缩js的时候,同时生成一个“.map”文件,对压缩前的js诸如变量之类的内容做索引,页面加载min版的js,可以通过对应的.map文件找到压缩前的js文件,如果这是js再出错,可以直接将错误定位到压缩前的js文件内
怎么样,听起来是不是很棒
好,下面就详细讲一下用法
比如页面上有一个js文件:t.js,下面对t.js做压缩
1 2 3 4 5 | java -jar /usr/local/compiler.jar \ --js t.js \ --create_source_map t.js.map \ --source_map_format=V3 \ --js_output_file t.min.js |
其中,“create_source_map”就是生成.map文件的名字,“source_map_format”是source map的版本
完了页面,在页面调用t.min.js,故意制造个错误,这是你会发现,页面上的错误指示~~~还TM和以前一样
呵呵,因为还有两步我们还没做:
1. 手动往t.min.js结尾处加上下面这行,告诉浏览器.map文件所在的位置:
//@ sourceMappingURL=t.js.map
2. 开启浏览器的source map支持,悲剧的是,目前只有chrome支持source map,具体未知是在:
“开发者工具” -> “设置”(右下角齿轮) -> 勾选“Enable source maps”
ok了,这是再试试,一旦js报错,点击错误,就能定位到压缩前的js文件上
并且,在开发者工具里的“Sources”标签里,还能找到压缩前的js源码
————-
参考:http://www.csdn.net/article/2013-01-25/2813953-JavaScript-Source-Map
ps:关于.map文件内部各项内容的含义,我并没有仔细研究~~~反正只要设置正确,chrome就可以把错误定位到源js文件
mac系统下,使用node-gyp编译node.js扩展,总共两步:
1 2 | node-gyp configure node-gyp build |
悲催的是,两步居然都出了问题
第一步碰上的问题是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.' ]
xcode-select: Error: No Xcode is selected. Use xcode-select -switch <path-to-xcode>, or see the xcode-select manpage (man xcode-select) for further information.
Traceback (most recent call last):
File "/usr/local/lib/node_modules/node-gyp/gyp/gyp", line 18, in <module>
sys.exit(gyp.main(sys.argv[1:]))
//..................
Exception: Error 2 running xcode-select
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack at ChildProcess.onCpExit (/usr/local/lib/node_modules/node-gyp/lib/configure.js:420:16)
gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:91:17)
gyp ERR! stack at Process._handle.onexit (child_process.js:678:10)
gyp ERR! System Darwin 12.2.0
gyp ERR! command "node" "/usr/local/bin/node-gyp" "configure"
gyp ERR! cwd /JKL/MyWorld/node/c_m/helloWorld
gyp ERR! node -v v0.8.9
gyp ERR! node-gyp -v v0.8.3
gyp ERR! not ok
xcode-select: Error: No Xcode is selected. Use xcode-select -switch <path-to-xcode>, or see the xcode-select manpage (man xcode-select) for further information. |
第一反应是,node.js和Xcode有毛关系,google“path-to-xcode”,发现还真是有问题:我的系统曾经装过早期版本的xcode,是默认装在developer系统下,但是最新版本的xcode是在Applications目录里,虽然这对xcode没影响(至少我没发现),但是看起来是对里面的c++模块有影响,具体啥情况,我也不晓得~~只要知道解决方案就可以了:
重新设置xcode-select指到你的Xcode.app
1 | sudo xcode-select -switch /Applications/Xcode.app/ |
设置了xcode-select以后,“node-gyp configure”通过,但是“node-gyp build”再次出现问题:
1 2 3 4 5 6 7 8 | gyp info it worked if it ends with ok gyp info using node-gyp@0.8.3 gyp info using node@0.8.9 | darwin | x64 gyp ERR! build error gyp ERR! stack Error: not found: make gyp ERR! stack at F (/usr/local/lib/node_modules/node-gyp/node_modules/which/which.js:43:28) //.......... gyp ERR! not ok |
对configure/make这种玩意本来就不熟,于是有迷茫了一阵,继续google,发现据说是缺少GCC(GNU Compiler Collection,GNU编译器集合),还是需要通过Xcode解决:
打开Xcode -> Preferences -> Downloads -> Command Line Tools -> install -> Reboot
下载这个100多M的东西,用了些时间,然后再次“node-gyp build”
~~~ok
来看看这段简单的dom操作,clone子节点操作代码:将div内的子节点挨个clone一次,然后再插入这个div内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <body> <a href="javascript:void(0);" id="start">start</a> <div id="test"> <div>t1</div> <div>t2</div> </div> <script type="text/javascript"> window.onload = function(){ document.getElementById('start').onclick = function(){ var div = document.getElementById('test'), childs = div.getElementsByTagName('div'); for(var i = 0; i < childs.length; i++){ var d = childs[i].cloneNode(true); div.appendChild(d); } }; }; </script> </body> |
试着执行一下,你会发现,浏览器卡死了 🙁
为什么哪?
因为通过getElementsByTagName取得的节点集合childs是动态的,当继续往父节点div内添加子节点时,也同时将这些节点添加到了childs的里面~~所以循环变成了无限的
对于这个例子,你可以在循环前将将childs.length保存到一个变量里面,然后在循环时,将i与这个变量比较
当然,这样并非真的解决了问题,比如你如果是要通过insertBefore插入节点,即插入的节点不是在已有的节点后面,上面虽然不会死循环,但循环仍然会乱掉,原因很简单:childs是动态的
正切的做法是重新定义一个childs数组,让后将原来的DOM对象childs里的节点,放到js数组childs里面,这时的childs就不再是动态的了
