事件代理原理不多记录了,直接上代码来说明案例情况
比如有一个子组件
<div
:class="['item', { 'active': index === curIndex}]"
:data-index="index"
>
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
子组件内部有icon区域,有header区域,有content区域,用户点击时,绑定在父组件上的代理事件,获取的target指向为这些区域的标签元素,而不是最外层的标签元素.
事件代理是利用事件冒泡的机制,将事件处理程序绑定到父元素,然后通过事件对象的target属性来判断实际触发事件的子元素。但是当子元素嵌套时,target可能会指向最内层的元素,也就是具体的icon区域,有header区域,有content区域,而不是外层的包裹标签,实际开发中,就会有个需求,无论用户点击的是包裹标签(例子中是有item类的div)内部的哪个子元素,都能获取到对应的包裹标签元素作为目标元素.
这里用到了 Element.closest() ,MDN的描述为:
Element.closest()方法用来获取:匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)。如果匹配不到,则返回null。
用在代理方法中,就是使用closest(),从当前点击元素对象上,开始向上查找匹配指定选择器的第一个祖先元素,这里的子组件外层有一个 item 类
const itemClick = function (e) {
const tar = e.target.closest(".item");
// const tar = findParent(e.target);
if(tar) {
const classList = tar.classList;
if ( classList.contains('item') ) {
const index = parseInt(tar.dataset.index);
curIndex.value = index;
}
}
}
当然也可以自己写个方法,手动循环查找父元素
const findParent = function (el) {
while (el && !el.classList.contains('item')) {
el = el.parentElement;
if (el === null) break; // 到达文档根元素时退出
}
return el;
}
通过上面的方法,来更好地在真实开发场景中应用事件代理