js事件委托

概述

事件委托或事件代理,就是利用事件冒泡,值得是指定一个事件处理,就可以管理某一类型的所有事件。

实现

子节点实现相同的功能

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

实现点击li的时候,弹出123

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

上面的代码需要多次操dom,用事件代理的方式实现

window.onload = function(){
  var oUl = document.getElementById("ul1");
    oUl.onclick = function(){
    	alert(123);
    }
}

用父级ul做事件处理,当点击li的时候,由于冒泡原理,事件就冒泡的ul上。但是点击ul的时候也会触发事件。我们用event提供的target来解决(IE中是srcElement)来获取节点的位置,我们并不知道节点的名字是什么,可以用nodeName来获取具体的标签名,这是返回的是大写,我们做好转化成小写来进行比较。

window.onload = function(){
    var oUl = document.getElementById("ul1");
    oUl.onclick = function(ev){
    	var ev = ev || window.event;
    	var target = ev.target || ev.srcElement;
    	if(target.nodeName.toLowerCase()=='li'){
    		alert(124);
    		alert(target.innerHTML);
    	}
    }
}

这样写的话只有点击li的时候会触发事件,点击ul的时候不会。
在FireFox浏览器中,事件绑定的函数要获取到事件本身,需要从函数中传入,而IE等浏览器则可以直接使用event或者window.event得到事件本身。

子节点实现的不同的效果

<div id="box">
	<input type="button" id="add" value="添加" />
	<input type="button" id="remove" value="删除" />
	<input type="button" id="move" value="移动" />
	<input type="button" id="select" value="选择" />
</div>
window.onload = function(){
    var Add = document.getElementById('add');
    var Remove = document.getElementById('remove');
    var Move = document.getElementById('move');
    var Select = document.getElementById('select');

    Add.onclick = function(){
    	alert('添加');
    }
    Remove.onclick = function(){
    	alert('删除');
    }
    Move.onclick = function(){
    	alert('移动');
    }
    Select.onclick = function(){
    	alert('选择');
    }		
}

普通的方法将要操作四次dom,下面用事件委托进行优化

window.onload = function(){
    var oBox = document.getElementById('box');
    oBox.onclick = function(ev){
    	var ev = ev || window.event;
    	var target = ev.target || ev.srcElement;
    	if(target.nodeName.toLowerCase()=='input'){
    		switch(target.id){
    			case 'add':
    				alert('添加');
    				break;
    			case 'remove':
    				alert('删除');
    				break;
    			case 'move':
    				alert('移动');
    				break;
    			case 'select':
    				alert('选择');
    				break;
    		}
    	}
    }	
}

一次dom操作就可以完成所有效果

新添加的节点

上面讨论的都是已有的节点,那么新添加的节点,能实现事件吗
一个正常添加节点的方法:

<input type="button" name="" id="btn" value="添加" />
<ul id="ul1">
	<li>111</li>
	<li>222</li>
	<li>333</li>
	<li>444</li>
</ul>

完成鼠标移入,li的背景色变成红色,移出变成白色,点击按钮新添加一个li

window.onload = function(){
    var oBtn = document.getElementById('btn');
    var oUl = document.getElementById('ul1');
    var aLi = oUl.getElementsByTagName('li');
    var num = 4;

    for(var i=0;i<aLi.length;i++){
    	aLi[i].onmouseover = function(){
    		this.style.background = 'red';
    	}
    	aLi[i].onmouseout = function(){
    		this.style.background = '#fff';
    	}
    }

    oBtn.onclick = function(){
    	num++;
    	var oLi = document.createElement('li');
    	oLi.innerHTML = 111*num;
    	oUl.appendChild(oLi);
    }
}

但是我们发现新添加的li是没有事件的,说明添加子节点的时候,事件并没有同时被添加进去。一般的解决方法是,将for循环用一个函数包起来,命名为mHover。

window.onload = function(){
   var oBtn = document.getElementById('btn');
    var oUl = document.getElementById('ul1');
    var aLi = oUl.getElementsByTagName('li');
    var num = 4;

    function mHover(){
    	for(var i=0;i<aLi.length;i++){
	    	aLi[i].onmouseover = function(){
	    		this.style.background = 'red';
	    	}
	    	aLi[i].onmouseout = function(){
	    		this.style.background = '#fff';
	    	}
	    }
    }
    mHover();
    

    oBtn.onclick = function(){
    	num++;
    	var oLi = document.createElement('li');
    	oLi.innerHTML = 111*num;
    	oUl.appendChild(oLi);
    	mHover();
    }
}

上面的方法虽然实现了功能,但是增加了dom操作,下面用事件委托的方式优化。

window.onload = function(){
    var oBtn = document.getElementById('btn');
    var oUl = document.getElementById('ul1');
    var aLi = oUl.getElementsByTagName('li');
    var num = 4;

    oUl.onmouseover = function(ev){
    	var ev = ev || window.event;
    	var target = ev.target || ev.srcElement;
    	if(target.nodeName.toLowerCase=='li'){
    		target.style.background='red';
    	}
    }

    oUl.onmouseout = funtion(ev){
    	var ev = ev || window.event;
    	var target = ev.target || ev.srcElement;
    	if(target.nodeName.toLowerCase=='li'){
    		target.style.background='#fff';
    	}
    }

    oBtn.onclick = function(){
    	num++;
    	var oLi = document.createElement('li');
    	oLi.innerHtml = 111*num;
    	oUl.appendChild(oLi);
    }
}

上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都可以在js里面执行,这样可以大大的减少dom操作,这才是事件委托的精髓。

其他场景

ul>li>div>p,div占满li,p占满div,还是给ul绑定事件,怎么判断是点击是li,e.target可能是p,也可能是div,怎么判断?

<ul id="test">
	<li>
		<p>111111111</p>
	</li>
	<li>
		<div>
			22222222222
		</div>
	</li>
	<li>
		<span>333333333333</span>
	</li>
	<li>444444444444</li>
</ul>
window.onload = function(){   
   var oUl = document.getElementById('test');
    oUl.onclick = function(ev){
    	var target = ev.target;
    	while(target!==oUl){
    		if(target.tagName.toLowerCase()=='li'){
    			console.log('li click');
    			break;
    		}
    		target = target.parentNode;
    	}
    }
}

核心在while循环部分,从里往外冒泡,知道currentTarget为止,当target是li的时候,就可以执行相应的事件了,终止循环。

适合事件委托的事件

click,mousedown,mouseup,keydown,keyup,keypress

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值