ejohn在最新的一篇博客说到 jquery closest 增加参数数组类型 , 并提到了live这个功能,其他框架库我还没有见过这个功能,记得以前jq官方没有live时,听过过它的一个插件livequery,可以对并不存在的dom结点绑定事件,觉得很有意思,这次就一并简单研究了下:
livequery:
使用:
$('div.noexists').livequery('click', function(){ alert(this.innerHTML); } );
那么即使当前页面没有类为 noexists 的 div 结点,以后当你添加后,
$(document.body).append("<div class='noexist'>test</div>");
事件会自动注册到这个结点上面去。
原理:
看完其源代码后,觉得实现确实不是很难,基本原理就是修改jquery原来的所有DOM更改操作:'append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove',在进行官方操作后运行自己的代码:
对之前的运行过 livequery 的所有选择符比如这里的div.noexists全部取出来,然后判断是否已经注册过指定事件处理了,如果没有就注册。
其中的细节还有对livequery 选择符的注册队列管理,以及清除,暂停一系列机制。
优点:
将创建添加元素与事件注册处理,分隔开来,对一类元素设置好livequery后,以后只要专注与内容修改即可,程序会更加有条理。
缺点:
每次更改任意部分结点内容都要将livequery 选择符重新判断一次,对于性能要求严格以及livequery选择符很多时慎用。
live:
jquery大概在1.3后实现了live,功能与livequery核心大致相同,但实现迥异,jquery利用了delagation,即事件委托机制,早先将事件全部委托给document处理,1.4以后事件委托给元素的context处理,性能更有提高。(As of jQuery 1.4, event bubbling can optionally stop at a DOM element "context")
使用:
$('div.noexists').live('click', function(){ alert(this.innerHTML); } );
运行后,click事件注册到 $('div.noexists').context即document上面,当click事件发生时,传播到document处理,从click事件的源目标(target)一直往上找,将第一个符合div.noexists的结点做为事件处理函数的this上下文然后执行事件处理函数。
优化:
这次,ejohn之所以要对closest修改,就是因为当多个live选择符时,当触发事件时原先是对每个选择符都执行上述操作:
jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){ if ( check.test(fn.type) ) { var elem = jQuery(event.target).closest(fn.data)[0]; if ( elem ) elems.push({ elem: elem, fn: fn }); } });
这样的话对于下列代码:
<html> <body> <div id="main"> <div id="test"> <div id="mouseme"></div> </div> </div> </body> </html> $("#mouseme").live("mousemove", ...) $("#main").live("mousemove", ...) $("body").live("mousemove", ...) // (plugin A) $("body").live("mousemove", ...) // (plugin B)
在jquery1.3.2中:
1. #mouseme check on #mouseme (load Sizzle)
2. Return.
3. #main check on #mouseme (load Sizzle)
4. Walk up tree.
5. #main check on #test (load Sizzle)
6. Walk up tree.
7. #main check on #main (load Sizzle)
8. Return.
9. body check on #mouseme (load Sizzle)
10. Walk up tree.
11. body check on #test (load Sizzle)
12. Walk up tree.
13. body check on #main(load Sizzle)
14. Walk up tree.
15. body check on body (load Sizzle)
16. Return.
17. body check on #mouseme (load Sizzle)
18. Walk up tree.
19. body check on #test (load Sizzle)
20. Walk up tree.
21. body check on #main(load Sizzle)
22. Walk up tree.
23. body check on body (load Sizzle)
24. Return.
25. Sort all element results.
26. Loop through the results to trigger.
jquery1.4 closest增加了参数数组类型 :
while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { match = matches[selector]; if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { ret.push({ selector: selector, elem: cur }); delete matches[selector]; } } cur = cur.parentNode; } }
则当前目标对于所有选择符只需walk up tree一次即可!
1. #mouseme check on #mouseme (load Sizzle)
2. #main check on #mouseme (load Sizzle)
3. body check on #mouseme (load Sizzle)
4. Walk up tree.
5. #main check on #test (load Sizzle)
6. body check on #test (load Sizzle)
7. Walk up tree.
8. #main check on #main (load Sizzle)
9. body check on #main (load Sizzle)
10. Walk up tree.
11. body check on body (load Sizzle)
12. Return.
13. Loop through the results to trigger.
提高了效率 。