事件委托与事件冒泡

事件委托

 * 什么是事件委托?
  – 利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行
 * 为什么要用事件委托
  – 正常来说直接给DOM设置事件处理程序就好了,但是有很多DOM需要设置事件处理,比如有100个li需要设置,这时候因为需要与DOM节点进行交互访问DOM次数就变多,就会延长整个页面的交互就绪时间;这时候用到事件委托,将所有事件放到js程序里这时候与DOM的操作就只需要进行一次就够了
 * 事件委托的原理
  – 事件委托是利用事件冒泡原理来实现的
 * 事件委托的优点
  – 大量减少内存占用,减少事件注册
  – 实现在新增子项时无需在重新对其绑定(动态事件绑定)

案例展示

 一般的方法案例
  该方法进行多次DOM操作,首先获取到ul在通过遍历获取到所有的li,在给所以li绑定一个点击事件

<ul id="new_ul">
	<li>1111</li>
	<li>2222</li>
	<li>3333</li>
	<li>4444</li>
	<li>5555</li>
</ul>
window.onload = function(){
	let newul = document.getElementById('new_ul');
	let newli = newul.getElementsByTagName('li');
	for(let i = 0;i < newli.length;i++){
		newli[i].onclick =function(){
			alert(i+1);
		}
	}
}

 使用事件委托
  直接找到ul并绑定事件,当点击li时事件冒泡,因为ul有点击事件所以会触发

window.onload = function(){
	let newul = document.getElementById('new_ul');
		newul.onclick =function(){
			alert('a');
		}
}

 那么问题来了如果我想事件代理的效果跟直接点击节点一样怎么办
 Event对象提供了一个属性:target,可以返回事件的目标节点,target就可以表示为当前的事件操作的dom,但是不是真正操作dom
 兼容性:标准浏览器用ev.target,IE浏览器用event.srcElement
 利用target获取的是节点,我们还需要获得名称所以用nodeName,nodeName获取的是大写在进行小写化利用toLowerCase()转化成小写

window.onload = function(){
	let newul = document.getElementById('new_ul');
	newul.onclick =function(ev){
		let ev = ev || window.event;
		let target = ev.target || event.srcElement;
		if(target.nodeName.toLowerCase() == 'li'){
			alert(target.innerHTML);
		}
	}
}

 增加新节点,新节点会有事件效果吗

<input type="" name=""   value="" id='zhi'>
<input type="button" name="" value="增加" id='butt'>
<ul id="new_ul">
	<li>1111</li>
	<li>2222</li>
	<li>3333</li>
	<li>4444</li>
	<li>5555</li>
</ul>
window.onload = function(){
	let butt = document.getElementById('butt');
	let newul = document.getElementById('new_ul');
	let newli = newul.getElementsByTagName('li');
	let num = newli.length;
	newul.onclick = function(ev){
		var ev = ev||window.event;
		let target = ev.target || event.srcElement;
		if(target.nodeName.toLowerCase() == 'li'){
			alert(target.innerHTML);
		}
	}
	butt.onclick = function(){
		let xinli = document.createElement('li');
		let zhi = document.getElementById('zhi').value;
		xinli.innerHTML = zhi;
		newul.appendChild(xinli);
	}
}

通过实验证明新增的li是会触发ul的事件的

事件委托的注意事项

  – 使用“事件委托”时,并不是说把事件委托给的元素越靠近顶层就越好。事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时。如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失

事件冒泡

  – 当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window

<ul onclick="alert('ul_click')">
	<li onclick="alert('li_click')"><a href="" id="li_a">a</a></li>
</ul>
//正常的事件冒泡,这个会一直往上冒泡
window.onload = function(){
	let lia = document.getElementById('li_a');
	lia.onclick = function(){
		alert("a");
	}
}
//阻止事件冒泡
window.onload = function(){
	let lia = document.getElementById('li_a');
	lia.onclick = function(){
		alert("a");
		event.stopPropagation();
	}
}

阻止事件冒泡的方法有很多种,本文只采用了方便快捷的一种

方法总结

  – var ev = ev||window.event; 兼容性写法
  – let target = ev.target || event.srcElement; 获取目标节点
  – toLowerCase() 将字母小写
  – appendChild() 插入节点
  – target.nodeName 目标节点的名称(大写)
  – event.stopPropagation(); 阻止事件冒泡到DOM树上

标签

发表评论

您必须启用javascript才能在此处查看验证码