您的位置:首页 > 其它

delegate事件代理

2015-06-13 14:41 281 查看
如果用过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://runjs.cn/code/e6z48nm2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: