Jquery揭秘系列:谈谈bind,one,live,delegate,on事件及实现
在Jquery里面,我们用的最多的就是事件绑定了,事件绑定有多个函数。例如:bind,one,live,delegate,on等等。
on()
jQuery事件绑定.on()简要概述及应用
看源码发现bind()和delegate()都是由on()实现的。on()的描述如下:
在需要为较多的元素绑定事件的时候,优先考虑事件委托,可以带来性能上的好处。比如:
如上图,将click事件绑定在document对象上,页面上任何元素发生的click事件都冒泡到document对象上得到处理。
注意到.on()的描述中第二个可选参数:selector。如下图,添加了第二个参数,选择符button:
结果:
当事件冒泡到document对象时,检测事件的target,如果与传入的选择符(这里是button)匹配,就触发事件,否则不触发。
注意.on()也可以接收一个对象参数,该对象的属性是事件类型,属性值为事件处理函数。下面是官方文档的一个例子:
最后有一点,原先的live()方法,处理函数是默认绑定在document对象上不能变的,如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致较大的性能损失。而使用.on()
方法,事件只会绑定到$()
函数的选择符表达式匹配的元素上(上面我的例子中,为了简单绑定到了document),因此可以精确地定位到页面中的一部分,而事件冒泡的开销也可以减少。delegate()与on()同理,毕竟是用on()实现的:
bind( )方法用于将一个处理程序附加到每个匹配元素的事件上并返回jQuery对象。
.bind(eventType[, evnetData], Handler(eventObject))
其中,参数eventType是一个字符串,包含一个或多个javaScript事件类 型,例如click,submit或自定义事件的名称,指定多个事件类型时用空格分隔各个类型;eventData为Map类型,给出要传递给事件处理程 序的数据,handler指定触发该事件时要执行的函数,eventObject表示事件对象。
.bind()方法将事件处理程序handler附加到匹配元素集合中的每个元素的eventType事件上,如果需要,还可以向事件处理程序传递数据。
live( )方法将一个事件处理程序附加到与当前选择器匹配的所有元素(包含现有的或将来添加的)的指定事件上并返回jQuery对象。
.live(eventType,[eventData],handler)
其中,参数eventType是一个字符串,包含一个或多个javaScript事件类 型,例如click,keydown或自定义事件的名称,eventData是可选参数,为Map类型,给出要传递给事件处理程序的数据,该参数是在 jQuery1.4中添加的;handler是一个函数,当触发该事件时将执行这些函数
.live()方法将事件处理程序handler附加到每个匹配元素(包含当前存在的和将来添加的)的eventType事件上,必要时还可以使用参加eventData向事件处理程序传递数据。
.live()方法是基本的.bind()方法的一个变形,后者可以将事件处理程序附加到 元素·,当调用.bind()时,jQuery对象匹配的元素将被附加上事件处理程序,但以后添加的元素并不会被附加该事件处理程序,因此,还需要对这些 元素再次调用.bind()方法。
.one()方法将事件处理程序附加到匹配元素的指定事件并返回jQuery对象。所附加的事件处理程序最多只能执行一次。
.one(eventType,[eventData],handler(eventObject))
其中,参数eventType是一个字符串,包含一个或多个javaScript事件类 型,例如click,submit或自定义事件的名称,指定多个事件类型时用空格分隔各个类型;eventData为Map类型,给出要传递给事件处理程 序的数据,handler指定触发该事件时要执行的函数,eventObject表示事件对象。
.one()方法与.bind()类似,所不同的是,使用.one()绑定的事件处理程序在执行一次之后将自动取消绑定。
.delegate()方法基于一组特定的根元素将处理程序附加到匹配选择器的所有元素(现有的或将来的)的一个或多个事件上。
.delegate(selector,eventType[,eventData],handler)
其中,参数 selector是一个选择器,用于筛选触发事件的元素;eventType是一个字符串,指定一个或多个JavaScript事件类型(多个事件用空格 分隔),例如click,keydown或自定义事件名称;eventData为映射类型,表示要传递给事件处理程序的数据;handler表示触发该事 件时执行的函数。
.delegate()与.live()类似,可将每个事件的绑定委托给指定的DOM元素。
再说说区别:
-
bind是在dom树加载后,对元素的绑定,属于后期绑定。
-
one是在dom树加载后,对元素的绑定,和bind一样属于后期绑定,但是会在事件执行之后移除元素的绑定事件,事件只执行一次。
-
live 是先把事件绑定在document对象上面,通过事件冒泡,判断当前处于目标状态的元素是不是预绑定的那个元素对象,然后执行事件,属于前期绑定,元素可以是已存在的,也可以是动态添加的。
-
delegate绑定的元素可以是已经存在的,也可以是动态添加的。如果是已经存在的就会选定一个父元素,通过冒泡来触发指定子元素的事件。如果是动态添加的,就以document为父元素来触发冒泡事件。
- (注:这里所说的后期绑定指的是元素已经加载后,进行事件的绑定。前期绑定指的是元素尚未存在,为动态元素添加事件)
这几种方法推荐使用bind和delegate,因为live是绑定事件在document上面,然后通过冒泡查询元素执行事件,很耗性能。
它们的原生js实现 :
(function (context) { var _$ = function (selector) { return new _$.prototype.Init(selector); } _$.prototype = { Init: function () { var arr = Array.prototype.slice.call(arguments); if (arr.length > 0) { if (typeof arr[0] == "string") { this.element = document.getElementById(arr[0]); } else if (Object.prototype.toString.call(arr[0])=="object Object") { this.element = arr[0]; } } }, bind: function (type, fn) { if (this.element) { if (document.addEventListener) { this.element.addEventListener(type, fn, false); } else if (document.attachEvent) { this.element.attachEvent('on' + type, fn); } else { this.element['on' + type] = fn; } } }, unbind: function (type, fn) { if (this.element) { if (document.removeEventListener) { this.element.removeEventListener(type, fn, false); } else if (document.attachEvent) { this.element.detachEvent('on' + type, fn); } else { this.element['on' + type] = null; } } }, one: function (type, fn) { var self = this; if (this.element) { if (document.addEventListener) { this.element.addEventListener(type, function () { self.element.removeEventListener(type, arguments.callee, false); fn(); }, false); } else if (document.attachEvent) { this.element.attachEvent('on' + type, function () { self.element.detachEvent('on' + type, arguments.callee); fn(); }); } else { this.element['on' + type] = function () { self.element['on' + type] = null; fn(); }; } } }, live: function (type, fn) { var self = this; if (document.addEventListener) { document.addEventListener(type, function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.id == self.element.id) { fn(); } }, false); } else if (document.attachEvent) { document.attachEvent('on' + type, function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.id == self.element.id) { fn(); } }); } else { document['on' + type] = function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.id == self.element.id) { document['on' + type] = null; fn(); } }; } }, delegate: function (flag, type, fn) { var self = this; if (document.addEventListener) { self.element.addEventListener(type, function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.tagName.toLowerCase() == flag) { fn(); } }, false); } else if (document.attachEvent) { self.element.attachEvent('on' + type, function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.tagName.toLowerCase() == flag) { fn(); } }); } else { self.element['on' + type] = function (e) { var evt = e || window.event; var target = evt.srcElement || evt.target; if (target.tagName.toLowerCase() == flag) { fn(); } }; } } } _$.prototype.Init.prototype = _$.prototype; context.$ = _$; })(window);