如果用过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