前置知识: Dom事件模型
首先,让我们来看看这段html代码
<ul>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
</ul>
需求是:当点击li的时候里面的文字变蓝
当然,我们可以一个一个绑定事件
li1.addEventListener('click',()=>{
li1.style.color = 'blue'
});
li2.addEventListener('click',()=>{
li2.style.color = 'blue'
});
......
......
但这样有几个缺点:
1. 占用内存
2. 代码量繁多,如果有100个li甚至更多的话岂不是要花费大量的无用时间
那我们换个角度,如果监听li复杂的话,我们是不是可以来监听它们的祖先元素,根据事件冒泡,并且运用条件语句和e.target来判断点击的是否是li标签,如果是的话,则执行对应的事件。
ul.addEventListener('click',(e)=>{
if(e.target.tagName.toLowerCase() === 'li'){
e.target.style.color = 'blue'
}
})
这样的话,监听的元素从原来所有的li变成一个ul,这样既减少了占用的内存,提高了性能,也减轻了代码量。
让我们来看第二段html代码
<ul>
<li>点我,我的文字会变蓝</li>
<button>点我,会增加li</button>
</ul>
需求是:每次点击按钮增加的li上都要绑定相同的监听事件
这次需要监听的是动态元素,我们也可以用相同的方法去委托ul去监听动态元素
ul.addEventListener('click',(e)=>{
if(e.target.tagName.toLowerCase() === 'li'){
e.target.style.color = 'blue'
}
})
这种把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务的技术手段就叫做
事件委托
由上面的事例可以看出事件委托的优点:
1.可以监听动态的元素
2.减少监听数量
3.提高性能
注意
<ul id="ul">
<li id="li1"> <span>点我,我的文字会变蓝</span></li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
<li>点我,我的文字会变蓝</li>
</ul>
当li中有其他的元素例如span时,我们点击的元素就会变为span,而不是li,就不会执行事件。所以我们需要嵌套地找出点击的元素的祖先元素是否是li
ul.addEventListener("click", (e) => {
let x = e.target;
while (x.tagName.toLowerCase() !== "li") {
if (x === ul) {
x = null;//作为是否找到对应元素的判断,没找到,则是null;
break;//到监听的父节点,还是没有找到li,退出循环,防止死循环;
}
x = x.parentNode;
};
if (x) {
x.style.color = "blue";
}
});