什么是事件委托
利用冒泡的机制,将某一类型的操作委托给父级统一管理,然后根据事件源(target)去完成某一子项的操作。
为什么要使用事件委托
dom的事件我们习惯上直接绑定到dom上,但是如果需要绑定事件的dom很多,那会直接影响页面的性能,频繁的对dom进行事件绑定,本身就是消耗性能的事情。从资源消耗角度来看,每个方法本身都是对象,都要占据空间,所以方法越多,空间耗费越大,那么利用委托就是势在必行的。例如,有n个li要执行click操作,我们可能会使用for循环来完成,在操作上似乎没有多麻烦,但如果考虑前面提到的性能和资源耗费方面,那就是非常严重的了,尤其是当n很大的时候。这时候我们就需要委托,就是直接将li的click都绑定到li的父级ul上,由父级进行统一管理,用事件源(target)作为判断条件,以便于对某一个li做操作。
示例1
<!-- 示例1 -->
<ul id='demo1'>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var domUl1 = document.getElementsByTagName('ul')[0];
var domLi = domUl1.getElementsByTagName('li');
// 不使用委托
for (var i = 0; i < domLi.length; i++) {
domLi[i].onclick = function () {
// 这里其实也存在一个闭包问题,i共用,在使用时已变成5
console.log('不委托', i);
}
}
</script>
不使用委托,点击li的结果:
使用委托,向ul绑定事件,通过事件源判断对具体某个li进行操作。如果你对事件源还不了解,可以console.log(事件源)
查看一下。
var domUl1 = document.getElementById('demo1');
domUl1.onclick = function (event) {
var event = event || window.event; // 事件对象,保证低版本ie兼容性
var target = event.target || event.srcElement; // 事件源,保证低版本ie兼容性
console.log('委托', target.innerHTML);
}
使用委托后,点击li的结果:
示例2
对于新加入节点,在不使用委托的情况下,对li利用for循环绑定的事件在新结点上将不会生效,除非重新执行for循环,再次绑定才有效。
<!-- 不使用委托,新增元素不会绑定方法 -->
<div>
<input type="button" value='添加li' onclick="addLi()" />
<ul id='demo2'>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script>
var domUl2 = document.getElementById('demo2');
var domLi2 = domUl2.getElementsByTagName('li');
var n = 5;
//鼠标移入值加1,移出值减1
for (var i = 0; i < domLi2.length; i++) {
domLi2[i].onmouseover = function (e) {
// this指向触发方法的dom
this.innerHTML++;
};
domLi2[i].onmouseout = function (e) {
// this指向触发方法的dom
this.innerHTML--;
}
}
// 添加新i
function addLi() {
var domLiItem = document.createElement('li');
domLiItem.innerHTML = ++n;
domUl2.appendChild(domLiItem);
}
</script>
这里我们对li添加onmouseover 和 onmouseout 事件,使li的值“++”或“–”,当点击【添加li】按钮新增li后,新增的li并不会触发之前绑定的事件, 除非我们在添加li后重新执行for循环绑定,这不仅让代码变得冗余,也浪费性能。**使用委托,对于新增元素添加的事件处理函数依然生效。**如下:
// 添加新i
function addLi() {
var domLiItem = document.createElement('li');
domLiItem.innerHTML = ++n;
domUl2.appendChild(domLiItem);
}
// 委托------------
domUl2.onmouseover = function (event) {
var event = event || window.event; // 事件对象,保证低版本ie兼容性
var target = event.target || event.srcElement; // 事件源,保证低版本ie兼容性
if (target.nodeName === "LI") { // nodeName判断节点具体时什么元素
target.innerHTML++;
}
}
domUl2.onmouseout = function (event) {
var event = event || window.event; // 事件对象,保证低版本ie兼容性
var target = event.target || event.srcElement; // 事件源,保证低版本ie兼容性
if (target.nodeName === "LI") { // nodeName判断节点具体时什么元素
target.innerHTML--;
}
}
示例3
对于子元素都事件执行内容不同,但事件相同的委托
<!-- 不使用委托,当子元素较多的时候,添加的事件越多 -->
<div id="demo3">
<input type="button" id='add' value="添加">
<input type="button" id='modify' value="修改">
<input type="button" id='del' value="删除">
</div>
<script>
var add = document.getElementById("add");
var modify = document.getElementById("modify");
var del = document.getElementById("del");
add.onclick = function () {
console.log('add');
};
modify.onclick = function () {
console.log('modify');
};
del.onclick = function () {
console.log('del');
};
</script>
使用委托后的代码:
// 委托
var demo3 = document.getElementById("demo3");
demo3.onclick = function (event) {
var event = event || window.event;
var target = event.target || event.srcElement
switch (target.id) {
case 'add':
console.log('add');
break;
case 'modify':
console.log('modify');
break;
case 'del':
console.log('del');
break;
}
}
示例4
多层嵌套,对某一层绑定事件。这里是对li绑定事件
<ul id="demo4">
<li>
<p>我是ul下的li下的p标签</p>
</li>
<li>
<a href="https://blog.csdn.net/Kindergarten_Sir">我是ul下的li下的a标签</a>
</li>
<li>
<div>我是ul下的li下的div标签</div>
</li>
<li>我是ul下的li标签</li>
</ul>
<script>
var demo4 = document.getElementById("demo4");
demo4.onclick = function (event) {
var event = event || window.event; // 事件对象,兼容低版本ie
var target = event.target || event.srcElement; // 事件源,兼容低版本ie
event.preventDefault();
while (target.nodeName !== 'LI') {
target = target.parentNode; // 父级
}
console.log('我是li');
}
</script>
以上是4种不同情况的委托。
相关学习内容推荐:你知道阻止默认行为、冒泡的封装吗?
相关学习内容推荐:你知道事件执行顺序,捕获、冒泡吗?
如果对你有帮助,可以点赞、收藏+关注哦~😘