一、定义:事件代理(事件委托):指当有大量子元素触发事件时,将事件监听器绑定在父元素进行监听,(真正绑定事件的是外层元素,⽽不是⽬标元素)此时数百个事件监听器变为了一个监听器,提升了网页性能。
二、本质:通过冒泡原理来实现的:
1.事件分为三个阶段: 先捕获,后目标,再冒泡;只能有一个阶段触发程序执行
2.事件经过的所有元素都没有被处理,这个事件就会消失
3.事件的传递过程是与结构上的嵌套关系有关,而非视觉上的嵌套关系
(从上往下)事件捕获:嵌套关系的元素,会存在事件捕获的功能,同一事件自父元素捕获至子元(从下往上)事件冒泡:嵌套关系的元素,会存在事件冒泡的功能,同一事件自父元素冒泡至子元素
三、举个例子:
现想通过点击按钮添加新列表4,5,6,但是由于是事件已经是绑定完后才新添加上去的,没有得到事件绑定,我们点击新添加的列表时就不会出现像点击列表123时打印的效果,这时候我们就要用到事件代理。将原本应该绑定在子元素当的点击事件绑定到父元素身上。
<ul>
<li class="myli">列表1</li>
<li class="myli">列表2</li>
<li class="myli">列表3</li>
</ul>
<button>添加li</button>
<script>
let myli = document.querySelectorAll(".myli");
let but = document.querySelector("button");
let ul = document.querySelector("ul");
let num = 3;
but.onclick = function () {
let li = document.createElement("li");
num++;
li.innerHTML = "列表" + num;
li.className = "myli";
ul.appendChild(li);
}
for (let i = 0; i < myli.length; i++) {
myli[i].onclick = function(){
console.log(myli[i].innerHTML);
}
}
</script>
此时我们点击新增列表4 5 是不会出现打印效果的,这是因为我们只将点击事件绑定到了原本有的子元素身上,新增的子元素没有得到事件绑定。所以我们要通过事件代理来实现让新的子元素也能有打印的效果,其本质是通过冒泡原理来实现的:将子元素上的事件冒泡到父元素身上让其一样能被实现。
<body>
<ul>
<li class="myli">列表1</li>
<li class="myli">列表2</li>
<li class="myli">列表3</li>
</ul>
<button>添加li</button>
<script>
let myli = document.querySelectorAll(".myli");
let but = document.querySelector("button");
let ul = document.querySelector("ul");
let num = 3;
but.onclick = function () {
let li = document.createElement("li");
num++;
li.innerHTML = "列表" + num;
li.className = "myli";
ul.appendChild(li);
}
// for (let i = 0; i < myli.length; i++) {
// myli[i].onclick = function(){
// console.log(myli[i].innerHTML);
// }
// }
//target:事件对象里面的属性 点击事件发生后存的元素节点
ul.onclick = function (e) {
// console.log(111);
//实现当前被点击的元素(列表)时打印
if (e.target.className == "myli") {
console.log(e.target.innerHTML);
}
}
</script>
</body>
四、总结:
优点:
1.提高性能,节约内存
2.新添加的子元素也可以绑定上事件
局限性:
1.有些事件(没有冒泡特性的)不可以用事件代理进行绑定,比如focus、blur
主要解决的问题:
解决静态的事件绑定问题;解决业务相同,而性能消耗却更高的问题。
适合用事件代理的事件:
click、mousedown、mouseup、keydown、keyup、keypress