1.使用背景
当需要批量添加事件监听时,比如点击每个li都将变为字体变为红色。
目标效果如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul id="list">
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
</ul>
<script>
var oList = document.getElementById('list');
var lis = oList.getElementsByTagName('li');
// 书写循环语句,批量给元素添加监听
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
// 在这个函数中,this表示点击的这个元素
this.style.color = 'red';
};
}
</script>
</body>
</html>
使用for循环可以将每个li都添加按钮点击事件,但是每个li都是一个函数,函数本身是会占用内存的,于是接下来我们将介绍事件委托。
2.事件委托机制
-
利用事件冒泡机制,将后代(比如li)元素事件委托给祖先(ul)元素。
-
事件传播是:先从外到内捕获,然后从内到外冒泡。
-
而事件监听有两种实现方式
-
onxxx为DOM0级事件监听,只能监听冒泡阶段。即如果给元素设置相同的两个或多个同名事件,后面的会覆盖先写的。
-
另一种方式是addEventListener()方法,DOM2级事件监听,
DOM.addEventListener('click',function(){},true);
true表示监听捕获阶段,默认为false,监听冒牌阶段。
3.实现批量添加事件监听
实现点击每个li改变颜色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul id="list">
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
</ul>
<script>
var oList = document.getElementById('list');
// var lis = oList.getElementsByTagName('li');
oList.onclick = function(e){
e.target.style.color = 'red';
}
</script>
</body>
</html>
注意:e.target属性触发此事件的最早元素,即用户真正点击的那个元素
e.currentTargent属性事件处理程序附加到的元素(跟this类似),表示祖先本身
4.事件委托的使用场景
- 当有大量类似元素需要批量添加事件监听时,可以减少内存开销
- 当有动态元素节点上树时,可以让新上树的元素具有事件监听。下面将有个小案例。
实现如下效果,动态添加li元素,然后点击每个li都触发删除事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
</style>
</head>
<body>
<input type="text" class="textInput">
<button id="btn">添加</button>
<ul class="list">
<li class="li">吃饭</li>
<li class="li">睡觉</li>
<li class="li">打豆豆</li>
</ul>
<script>
// 获取元素
var textInput = document.querySelector(".textInput")
var btn = document.querySelector("#btn")
var list = document.querySelector(".list")
var li = document.querySelectorAll(".li")
// 给按钮绑定点击事件
btn.onclick = function () {
var li = document.createElement("li");//创建li元素
li.className = "li";
li.innerHTML = textInput.value;
list.appendChild(li); //一定要将新增的li上树,不然点击事件对于新增的li无用,而且界面上也不会显示新增li
textInput.value = "";
}
// 给li绑定点击事件
//给祖先元素添加事件监听,利用冒泡机制,执行子元素。
list.onclick = function (e) {
list.removeChild(e.target);
}
</script>
</body>
</html>
5.注意事项
- onmouseenter和onmouseover都表示“鼠标进入”
- onmouseenter不冒泡;相当于后代元素动作附加给了祖先元素,就是祖先元素做了动作。比如鼠标放一个li相当于整个ul都放了。无法给每个li单独添加事件效果
- onmouseover冒泡
- 最内层元素(重复的元素比如li)不能再有额外的内层元素(比如span)了。因为当鼠标放在span上时,就会只有span项发生变化。