Jeekundo.com

以前端技术为主

Archive for December, 2009

知名站点js库使用情况统计

with 2 comments

jQuery Prototype YUI Mootools
微软
新版MSN
诺基亚
美国在线
Google Code
维基百科
W3C
戴尔
IBM
Digg
Mozilla.org
wordpress.org
以及wordpress博客后台
twitter
Netflix
alexa.com
ESPN
亚马逊
Box.net
QQ校友
QQ群
改版后的新浪NBA频道
豆瓣
土豆
Apple
CNN
Ajaxian
Adobe
37signals
开心网
优酷
Yahoo
mozilla.com
美味书签
WebQQ
淘宝
支付宝
口碑网
阿里中文站
阿里国际站
沃尔玛
Paypal
linkedin
phpMyAdmin
CNET
必应
wufoo.com
Ask.com
About.com

开源js库在这些顶尖站点中的使用率如此之高,可见一定有其过人之处。顺便推荐火狐的Library Detactor插件,在firefox的状态栏显示正在访问的站点使用的是什么js库。

Written by admin

December 20th, 2009 at 1:27 am

Posted in 前端技术

Tagged with , ,

javascript的事件绑定函数

without comments

最早给DOM节点绑定事件处理函数的方法是onevent方式,例如:

function handler()  {
    // 函数内容略
}
var aaa = document.getElementById('aaa');
aaa.onclick = handler;

这种方式具有不错的兼容性,但是缺点是最多只能给一个元素绑定一个函数,后面绑定的函数会把前面绑定的函数覆盖掉。

2001年Scott Andrew LePera写了一个包裹函数addEvent()来解决事件绑定的问题,后来被开发人员广泛采用。但是这个函数略显复杂,ppk在《ppk谈javascript》里面推荐的两个函数是这个函数的简化版:

function addEventSimple(obj,evt,fn) {
 if (obj.addEventListener)
  obj.addEventListener(evt,fn,false);
 else if (obj.attachEvent)
  obj.attachEvent('on'+evt,fn);
}

function removeEventSimple(obj,evt,fn) {
 if (obj.removeEventListener)
  obj.removeEventListener(evt,fn,false);
 else if (obj.detachEvent)
  obj.detachEvent('on'+evt,fn);
}

这个函数解决了给一个元素绑定多个事件处理函数的问题,然而缺点是在ie里面是事件处理函数里面的this关键字不能指向所绑定的DOM对象,而是指向window对象,即作用域错误。为了解决这个问题ppk在2005年举办了一个addEvent()函数重构竞赛。竞赛的优胜者是jQuery的作者john Resig,他的函数如下:

function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
    obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
    obj.addEventListener( type, fn, false );
}
function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
    obj.detachEvent( 'on'+type, obj[type+fn] );
    obj[type+fn] = null;
  } else
    obj.removeEventListener( type, fn, false );
}

这个函数修正了作用域,也有相配套的解除绑定函数,但是仍然有严重缺陷:他将字符串和函数相加以得到唯一的hash值,这种做法效率低下,并且不兼容某些手机浏览器。后来John Resig自己也说他不建议别人使用这两个函数(需要翻墙)。

在ppk的竞赛结束之后,作为评委的Dean Edwards也写了一个自己的addEvent()函数

// written by Dean Edwards, 2005
// http://dean.edwards.name/

function addEvent(element, type, handler) {
  // 为每个事件处理程序分配一个唯一的id
  if (!handler.$$guid) handler.$$guid = addEvent.guid++;
  // 为该元素的各种事件类型创建一个hash表
  if (!element.events) element.events = {};
  // 为每一个元素/事件对的所有事件处理程序创建一个hash表
  var handlers = element.events[type];
  if (!handlers) {
    handlers = element.events[type] = {};
    // 存储已经存在的事件处理程序(如果有的话)
    if (element["on" + type]) {
      handlers[0] = element["on" + type];
    }
  }
  // 将事件处理程序存储到hash表内
  handlers[handler.$$guid] = handler;
  // 剩下的任务交给一个全局的事件处理程序来搞定
  element["on" + type] = handleEvent;
};
// 一个用来分配唯一ID的计数器
addEvent.guid = 1;

function removeEvent(element, type, handler) {
  // 从hash表里面删除该事件处理程序
  if (element.events && element.events[type]) {
    delete element.events[type][handler.$$guid];
  }
};
function handleEvent(event) {
  var returnValue = true;
  // 取得event对象(IE使用了一个全局的事件对象)
  event = event || fixEvent(window.event);
  // 找到事件处理程序的hash表
  var handlers = this.events[event.type];
  // 执行各个事件处理程序
  for (var i in handlers) {
    this.$$handleEvent = handlers[i];
    if (this.$$handleEvent(event) === false) {
      returnValue = false;
    }
  }
  return returnValue;
};

function fixEvent(event) {
  // 增加符合W3C标准的事件模型
  event.preventDefault = fixEvent.preventDefault;
  event.stopPropagation = fixEvent.stopPropagation;
  return event;
};
fixEvent.preventDefault = function() {
  this.returnValue = false;
};
fixEvent.stopPropagation = function() {
  this.cancelBubble = true;
};

Dean Edwards的这个方法是相对来说最完美的一个方案,没有使用addEventListener和attachEvent就实现了多重函数的绑定,并且事件处理函数支持this关键字。

上面提到的这些都有提供相配套的解除绑定函数,但是大部分时候我们只需要绑定,不需要解绑,这种情况下下面这个简单的函数已经足够满足我们的需要了。

function addEvent( obj, type, fn ) {
        if (obj.addEventListener)
                obj.addEventListener(type, fn, false);
        else if (obj.attachEvent)
                obj.attachEvent('on' + type, function() { return fn.call(obj, window.event);});
}

大部分开源的js框架,如jQuery和YUI都有提供很方便的事件绑定接口,其实现的方式就复杂多了,当然功能也要强大得多。等有时间再研究。

Written by admin

December 13th, 2009 at 7:04 pm

Posted in 前端技术

Tagged with ,

谁说IE6不支持!important

with 2 comments

许多人认为ie6不支持!important,其实是被一条针对ie 6的css hack给误导了。

这条css hack是:

.test {
    height: auto !important;
    height: 500px;
}

.test的高度在其他浏览器里面是auto,而在ie6里面是500px,许多人在解释这条css hack之所以会生效是因为ie6不支持!important,误导了不少人。

其实ie6本身是支持!important的,下面换一种写法:

.test {
    height: auto !important;
}
.test {
    height: 500px;
}

发现ie6里面.test的高度也是auto,这说明ie6是支持!important的。那上面的hack之所以会生效是因为ie6的一个小小的bug,即当你把两条相同的声明放到同一个选择器里面的时候ie6才不认识!important。然而大部分时候,这个小小的bug并不影响我们在ie6内使用!important。

Written by admin

December 12th, 2009 at 11:27 pm

Posted in 前端技术

JS库开发原则

with 12 comments

1.保持无侵入式

html代码不必关心你的javascript在干什么。

2.严禁使用Object.prototype

这一条是如此重要以至于它有资格单独成为一条原则,对象是javascript最基本的构建元素,别把他弄乱了。

3.不要过度扩展

对javascript的内建对象的扩展越少越好。别误会,内建javascript对象本身有用的方法很少,你可能觉得有必要增加自己的一两个方法, 但是一两个对一个有创造力(js库)的程序员来说是不够的,停下来,只增加你真正想要的。越少去扩展内建对象,你与其他框架发生冲突的可能性就越少。

4.紧随标准

作为一个js库开发者,你在为javascript代码建立模式,然而模式在编程语言中意味着差劲,记住,关于javascript和DOM新 标准在不停地修订中,如果你打算去“修正”某些东西,那么先看看那些东西是否已经被修正过了。参考一下已有的解决方案。一旦跟随标准,请别掉队(比如,在 forEach方法中一个参数也不要漏掉)

5.或者跟随领袖

Mozilla引领javascript的潮流。该语言的发明 者,Brendan Eich仍然在改进它。js语言的新特性总是在Mozilla浏览器中最先出现,如果你打算给javascript语言增加新特性,请参考 Mozilla标准先。例如,如果你想增加一个遍历数组的方法,那么请把这个方法命名为forEach而不是each。而如果你是在补全缺失的功能,则要 严格参照现有标准(参见上一条)。

6.灵活一点

如果我想在不动你的js库源代码的情况下更改某个方法的行为,是否足够简单?如果还不够简单就让它更简单一点吧。

7.管理好内存

人们都在乎内存泄漏。把它做好。

8.去除浏览器检测

似乎浏览器厂商在增加新特性的竞争上永无休止。作为js库开发者,你应该紧跟最新的潮流,你不应该仅仅是偶尔看一下Ajaxian,你应该不知疲倦地阅读每一篇blog以便获知最新的hack,浏览器检测会让你越陷越深。

9.越小越好

许多js库已很成熟,其中一些已经被一些很重要的网站所采用。但不是每个人都在用2M的DSL宽带,所以保持你的js库小巧。最好能提供一个build页面让我能够快速的根据我的需要定制出我的js库。

10.第十条

很棒第十条,你总能信赖这一条。第十条是:可预见性。我应该可以根据方法的名字猜到它是干什么的,同样地,如果记不起一个方法的名字,我也应该可以猜得到。

11.附加的几条

1)文档,虽然讨厌但意义重大。

2)多用名字空间,这样我才不至于打电话骚扰你。

3)记住数以百万计的用户潜在用户可能会运行你的代码。

顺便声明,base2没有更改任何内建的javascript对象。

本文翻译自Rules For JavaScript Library Authors,这是Dean Edwards在开发base2时候的一些体会,对于在开发自己的js库的同学应该有较强的借鉴意义。Dean Edwards是公认的javascript高手,jQuery的作者Jhone Resig也很欣赏他。

Written by admin

December 8th, 2009 at 8:19 pm

Posted in 前端技术

Tagged with