[jQuery note.] 关于 bind, live 与 evnets 的笔记与 Plugin

其实我只是想做一个可以恶搞 Events 执行顺序的 plugin 而已(摊手)。
噗浪讨论串 1
噗浪讨论串 2

Plugin 先奉上,

(function($) {    $.fn.superbind = function(order, type, data, fn) {        if ( $.isFunction( data ) ) {            fn = data;            data = undefined;        }                 var order = (typeof order !== "number" || order < 0) ? 0 : order;                 return this.each(function() {            /* TODO: fire event before inline event.            if ( order === 0 && typeof $(this).attr("on"+type) === "function") {            }            */            var _ = setTimeout( function() {                var guid = 0;                $.each( $.cache, function() {                    if ( this.events && this.events[ "live" ] && this.events[ type ] ) {                        var len = this.events[ type ].length - 1;                        guid = parseInt(this.events[ "live" ][ len ].guid) + 1;                    }                });                $.each( $.cache, function() {                    var reorder = [], events_len = 0, reorder_len = 0;                    var obj = {                        data: data,                        guid: guid,                        handler: fn,                        namespace: "",                        type: type                    };                    if ( this.events && this.events[ type ] && !this.events[ "live" ] ) {                        events_len = this.events[ type ].length;                        order = (order > events_len) ? events_len : order;                                                 for(var i in this.events[ type ]) {                            if (order === events_len && parseInt(i) === events_len-1) {                                reorder.push(this.events[ type ][i]);                                reorder.push(obj);                                order = -1;                            } else if ( parseInt(i) === order || order === 0) {                                reorder.push(obj);                                reorder.push(this.events[ type ][i]);                                order = -1;                            } else {                                reorder.push(this.events[ type ][i]);                            }                        }                        this.events[ type ] = reorder;                        reorder = [];                        delete reorder;                    }                });            }, 20);                         return this;        });    };})(jQuery);

最近为了一些应用上的效果,所以特别研究了一下 Events 的资料。挖开 jQuery 之后才发现,这是一个很奇妙的世界(疑)。结合各家神人讨论,所以我来心得报告一下(喂)。特别感谢大泽木小铁、费拉诺兰大公鼎力相助(一拜)。

通常在 jQuery 里面,我们使用 Events 的作法,有三种:

// 1. 使用 bind 来绑定 event$("#elem").bind("click", function(e) { ... });// 2. 直接使用 event$("#elem").click(function(e) { ... });// 3. 使用 live 来绑定 event$("#elem").live("click", function(e) { ... });

其实在 DOM 中还有一种,则是:

<!-- 4. inline 的写法 --><div id="elem" onclick=" ... "> ... </div>

总共有四种方法,我们可以使用 Events。然而,这四种使用 Event 的优先顺序,分别是:

4 > 3 = 2 > 1

疑?不要问我为什么,因为实验的结果就是这样(喂)。当我们把 jQuery 三种使用 Events 的资料倾印出来的时候,会发现一件很神奇的事情,使用 bind/click 直接绑定的 Events,其资料是储存于元件本身,而使用 live 绑定时,资料会储存于 document 里面。再根据费拉诺兰大公所述,三者的资料都会储存于 $.cache 里面(使用阵列储存)。

所以,我们分别来看这些事情:

<!doctype html><html lang="en" class="no-js">    <meta charset="utf-8">    <style>    #main {      width: 400px;      height: 600px;      border: 1px solid #000000;      color: #ff3333;    }  </style>         <div id="container">        <div id="main" onclick="console.log(4);"></div>    </div>     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>    <script>!window.jQuery && document.write('<script src="./js/jquery-1.4.2.min.js"><\/script>')</script>    <script>    $(document).ready(function() {        $("#main").bind("click", function(e) {            console.log(3);            console.log($.data(this).events);        });        $("#main").click(function(e) {            console.log(2);            console.log($.data(this).events);        });        $("#main").live("click", function(e) {            console.log(1);            console.log($.data(this).events);            console.log($.data(document).events);            console.log("$.cache");            console.log($.cache);        });    });    </script>

以上的例子请使用 Chrome 或是 Firefox with Firebug 开启,资讯会记录在 console 底下。

依照 $.cache 的储存方法,他会将元素上的 click/bind 跟 live 分开存放,但是请注意,他并不会储存 DOM 里 inline 写法的 onclick,所以,并不能单纯使用这个方法去判断是否有该 Events 存在或是执行。此外,因为 $.cache 是以阵列的方式储存这些事情,而且他也并不能直觉的取得所绑定的对象,所以在资讯取出上,有相对麻烦的地方。

当你将 $.cache 列出来时,你会发现 live 这个方法,会产生一个相同的 event 方法,换句话说,你使用 bind/click 去绑定一个 Event 时,他只会有一个 event 方法,而,倘若你使用 live 去绑定一个 Event 时,他同时会衍生出一个该 Event 的 event 方法(超饶舌)。

// 这一段 Javascript 可以加在上述 live 的 function 底下 console.log("======================");for(i in $.cache) {    console.log("这是第 "+i.toString()+" 个 Event cache。");    var events = $.cache[i].events || null;    if(typeof events === "object") {        for(event in events) {            console.log("这是使用 "+event.toString()+" 绑定。");            console.log(events[event]);            if(events[event].length > 1) {                for(j in events[event]) {                    console.log("这是第 "+(parseInt(j)+1).toString()+" 个 Event 绑定。");                    console.log(events[event][j]);                }            }        }    }}

上述例子,点了方框之后,他会将 $.cache 的资讯列出来给你看。你会发现 live 会多一份 Event 的绑定,至于为什么?因为他是 live 啊(喂)!

这里有一个不小心实验出来的问题,当你使用 bind/click 时,倘若在 handler function 中使用了 return false; 的话,那么 live 所绑定的 Event 会略过不执行。原因是,因为 live 把 Event 偷偷地绑在 document 上面,由于 DOM 中 addEventListener 的规则,你使用 return false 就等同于 stopPropagation() 的意思(其实 return false 也会连带执行 preventDefault())。

所以,在 document 的子元件执行 stopPropagation(),想当然尔,document 所绑定的 Events 就不会被执行了,这一点可得小心为上。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章