如果用过jquery,相信对delegate方法的印象非常深刻,其前身是live方法。可以保证在节点还未出现就绑定监听事件。这么说可能不太明白。
首先看看下面例子:
<ul id="list"> <li class="listener" id="item1">liuf</li> <li id="item2">seven</li> <li id="item3">hehe</li> </ul><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
现在我们要给ul中的每一个li绑定click事件,最笨的办法如下:
//最笨的方法 addClickEvent($mi('#item1'),clickListener); addClickEvent($mi('#item2'),clickListener); addClickEvent($mi('#item3'),clickListener);
如果有很多li呢?难道我们一个一个的绑定吗?于是有了第二种方法,就是选中所有这个标签,用过each遍历来绑定,代码如下:
//稍微好些的方法 each($mini("#list").getElementsByTagName('li'),function(li){ addClickEvent(li,clickListener); });
这样看起来适合可以解决问题,那么如果出现以一种特殊情况呢?比如说通过触发某些事件后,多出了一个li或者移除了某些li,这样的话用上面方法就会失效。
这里就要想到事件冒泡了,事件冒泡的机制说简单点就是子元素响应后父元素也会响应,所以我们可以在父元素上绑定监听事件,代码如下:
//一种特殊情况 function renderList(){ $mi("#list").innerHTML="<li class='listener' id='new_item'>new item</li>"; } addClickEvent($mi("#btn"),renderList); //会发现上面的方法不能在新出现元素身上奏效。 //所以需要用到事件冒泡,给其父元素添加监听 addClickEvent($mi("#list"),clickListener);
那么只剩下最后一个问题了,就是如果我想要ul中指定class的标签响应事件怎么办?如果是统一在父元素绑定事件,那么其所有子元素都会响应,如何筛选呢?
这里我们定义了一个delegate代理函数,代码如下:
//事件代理 /** @para parentId 包裹容器的id @para selector 容器内元素的选择器,支持id和className @para fn 元素上要执行的函数 */ function delegate(parent, eventType, selector, fn) { //参数处理 if(typeof parent === 'string') { var parent = document.getElementById(parent); !parent && alert('parent not found'); } if(typeof selector !== 'string') { alert('selector is not string'); } if(typeof fn !== 'function') { alert('fn is not function'); } function handle(e){ //获取event对象 //标准DOM方法事件处理函数第一个参数是event对象 //IE可以使用全局变量window.event var evt = window.event ? window.event : e; //获取触发事件的原始事件源 //标准DOM方法是用target获取当前事件源 //IE使用evt.srcElement获取事件源 var target = evt.target || evt.srcElement; //获取当前正在处理的事件源 //标准DOM方法是用currentTarget获取当前事件源 //IE中的this指向当前处理的事件源 var currentTarget= e ? e.currentTarget : this; //在IE 9下 window.event 与 e 不同 evt没有currentTarget属性,e才有currentTarg alert("src id==="+target.id+"\n\ncurent target id=="+currentTarget.id); if(target.id === selector || target.className.indexOf(selector) != -1){ fn.call(target);//将目标this转变 } } parent[eventType]=handle;//为事件添加监听函数 }
这样就可以为指定子元素响应了。使用代码如下:
//但是单纯用冒泡只能默认父元素下所有子元素都影响,如何指定固定元素呢? //代理,监听list中指定class为listener的元素触发对应事件 delegate('list', 'onclick', 'listener', function(){ console.log(this); });
完整代码位置:
原文:http://blog.csdn.net/mevicky/article/details/46482565