Category Archives: 点点滴滴

Hello World 业界杂谈 点点滴滴

php ci快速入门

久闻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,这些都大大降低了新手的入门难度[赞]

Hello World 幻界杂谈 点点滴滴

jQuery()方法的第二个参数

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

Hello World 点点滴滴

setTimeout的精度

前几天刚发了一篇利用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

Hello World 点点滴滴

如何调试压缩后的js—— JavaScript Source Map的使用

随着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文件

Hello World 他山石 点点滴滴

你真的会用javascript吗?

偶然在csdn看到几个js的小题,考察的都是很基础的知识,拿来分享一下
1.

1
2
3
4
if (!("a" in window)) {
  var a = 1;
}
alert(a);

开始,我以为是1,后来试了下,结果是undefined,仔细看看,也对:js在执行是,会首先提取所有var的新变量,让后给其赋值undefined,并将其加入到当前的执行环境总,比如这里,程序还没执行,实际就有了window.a=undefined,所以“(“a” in window)==true”
2.

1
2
3
4
5
var a = 1;
var b = function a(x) {
  return x*x;
};
alert(a);

一直以为这种写法会报错,汗颜的是,前段时间去某家公司面试,还碰上了类似的题目,回来也没写写试试。
实际试了下,这里的alert仍然是1,这种写法,a只在function a的内部是function,但是如果在a内部调用a(x),会递归
3.

1
2
3
4
5
function a(x) {
    return x * 2;
}
var a;
alert(a);

呵呵,有了第一个题,这个就比较简单了,function
4.

1
2
3
4
5
function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);

这个也简单,arguments[2]就是a的替身,a会被修改为10
5.

1
2
3
4
function a() {
    alert(this);
}
a.call(null);

这里考察的是call的使用,正常call的参数是什么,里面的this就是什么(我也是这么理解的),但是关于call还有一条说明:如果call的参数是null或者undefined,里面的this仍然是当前执行环境,即window
————-
参考:http://bbs.csdn.net/topics/390300541