JS 事件委托(事件代理)是一种利用事件冒泡机制来优化事件处理的技术。
在 JavaScript 的事件流中,事件会经历捕获阶段、目标阶段和冒泡阶段。当一个元素上的事件被触发时,该事件会从最具体的目标元素(即被点击、鼠标悬停等操作的元素)开始向上冒泡,依次传递到它的父元素、祖父元素等,直到到达文档的根节点。事件委托就是利用这个冒泡机制,将事件处理程序绑定到目标元素的父元素或更外层的祖先元素上,当子元素上的事件触发时,会冒泡到外层的祖先元素,从而在外层元素的事件处理程序中进行处理。
<ul>
,当用户点击每个列表项<li>
时需要执行相应的操作。使用事件委托,只需要给<ul>
元素绑定一个点击事件处理程序,就可以处理所有<li>
元素的点击事件。id
为 parent-list
的 ul
元素,它是子元素 li
的父元素。ul
元素添加了一个 click
事件监听器。当在 ul
元素内部的任何地方发生点击事件时,这个事件监听器都会被触发。event.target
获取到了实际被点击的元素。然后使用 classList.contains
方法检查被点击的元素是否具有 item
类名,以此来判断是否是我们想要处理的子元素。如果是子元素,则打印出子元素的文本内容,表示该子元素被点击了。这样做的好处是,无论后续动态添加多少个新的 li
元素到 ul
中,都不需要为每个新元素单独添加点击事件监听器,它们的点击事件都会自动冒泡到父元素 ul
上,并被父元素的事件监听器处理,大大提高了代码的效率和可维护性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件代理</title>
<style>
.item {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<button onclick="addItem()">Add Item</button>
<ul id="parent-list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>
<script>
// 获取父元素
const parentList = document.getElementById('parent-list');
// 为父元素添加点击事件监听器
parentList.addEventListener('click', function (event) {
// 获取点击的目标元素
const target = event.target;
// 判断目标元素是否是子元素(这里根据类名判断)
if (target.classList.contains('item')) {
// 执行相应的操作
console.log('Clicked on item: ' + target.textContent);
}
});
function addItem() {
const oItem = document.createElement('li');
oItem.classList.add('item');
oItem.innerText = `Item ${parentList.children.length + 1}`;
parentList.appendChild(oItem);
}
</script>
</body>
</html>
// 原生JS
var ul = document.querySelector('ul');
function listen(element, eventType, targetElement, fn) {
element.addEventListener(eventType, function(e) {
// 先拿到当前事件的直接触发对象
var curTarget = e.target;
// 看它是不是使用者监听的目标对象类型
// 一旦发现不是,就执行循环
while(!curTarget.matches(targetElement)) {
// 先看看当前对象是不是和父元素相同
// 相同则把当前对象置为空,且不执行回调
if (curTarget === element) {
curTarget = null;
break;
}
// 不相同则把当前对象设置成自己的父对象
curTarget = curTarget.parentNode;
}
// 是,则先看当前对象有没有值,有值则执行回调函数
curTarget && fn(e, curTarget);
});
};
listen(ul, 'click', 'li', function(event, el) {
console.log(event, el);
});
// jquery
$("ul").on("click", "li", function(e) {
console.log($(e.target).html());
});
// 这个on事件是绑定在ul上面的,li是目标元素,
// on事件内部是通过e.target来判断点击元素是不是li的