JavaScript中的事件委托与事件冒泡

文章介绍了JavaScript中的事件委托,包括事件冒泡机制、如何在代码中实现事件委托以及其优点,如性能提升、代码简化和动态性。同时,也讨论了在特定场景下使用事件委托的局限性。
摘要由CSDN通过智能技术生成

简介

JavaScript中的事件委托是一种利用事件冒泡机制的技术。

它允许你将事件处理程序附加到一个父元素上,以代替将事件处理程序直接附加到每个子元素上。

当子元素触发事件时,事件将沿着DOM树向上传播,直到到达根元素。在这个过程中,父元素可以捕获到这个事件,然后根据触发事件的子元素的不同来执行相应的操作。

首先要明白什么是事件冒泡机制

事件冒泡机制

简介

事件冒泡机制是指在DOM中,当一个事件触发在某个元素上时,该事件会从最深的嵌套元素开始向外传播,直到传播到DOM树的根节点。

在这个过程中,父元素会逐级捕获到事件,然后执行相应的事件处理程序。这种事件传播的方式就像是从内到外的“冒泡”,因此称之为事件冒泡。

代码示例

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Bubbling Example</title>
<style>
    #parent {
        padding: 20px;
        background-color: #f0f0f0;
    }
    #child {
        padding: 10px;
        background-color: #ccc;
    }
</style>
</head>
<body>
<div id="parent">
    <div id="child">Click me!</div>
</div>
<script>
	// 获取父元素和子元素
	const parent = document.getElementById('parent');
	const child = document.getElementById('child');
	// 为子元素添加点击事件处理程序
	child.addEventListener('click', function(event) {
	    console.log("Child element clicked");
	    // 阻止事件继续冒泡到父元素
	    // event.stopPropagation();
	});
	// 为父元素添加点击事件处理程序
	parent.addEventListener('click', function() {
	    console.log("Parent element clicked");
	});
</script>
</body>
</html>

当我们点击child节点的时候,控制台会输出Child element clickedParent element clicked
当我们点击parent节点的时候,控制台只会输出Parent element clicked

事件冒泡机制效果生效

阻止冒泡事件

只需要在字类的事件绑定中加上event.stopPropagation()就可以防止事件冒泡的,在本文示例代码中只需把child的监听方法修改为下面

child.addEventListener('click', function(event) {
	    console.log("Child element clicked");
	    // 阻止事件继续冒泡到父元素
	    event.stopPropagation();
	});

![[事件冒泡机制阻止冒泡行为效果展示.gif]]

事件委托的实现

当我们有一个ul元素,其中包含多个li元素,我们想要为每个li元素添加点击事件处理程序时,可以使用事件委托和不使用事件委托的方式进行对比

不使用事件委托

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Delegation Demo</title>
</head>
<body>

<ul id="parent">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
</ul>

<script>
	// 获取所有的li元素
	const items = document.querySelectorAll('#parent li');
	
	// 为每个li元素添加点击事件处理程序
	items.forEach(item => {
	    item.addEventListener('click', () => {
	        console.log(`Clicked on ${item.textContent}`);
	    });
	});
</script>

</body>
</html>

不使用事件委托效果

使用事件委托

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Delegation Demo</title>
</head>
<body>

<ul id="parent">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
</ul>

<script>
	// 获取父元素ul
	const parent = document.getElementById('parent');
	
	// 添加点击事件处理程序到父元素ul上
	parent.addEventListener('click', (event) => {
	    // 检查点击的是否是li元素
	    if (event.target.tagName === 'LI') {
	        console.log(`Clicked on ${event.target.textContent}`);
	    }
	});
</script>

</body>
</html>

使用事件委托效果

区别

在不使用事件委托的情况下,我们需要为每个 li 元素分别绑定点击事件处理程序,这样会导致代码冗余,并且如果有大量的 li 元素,会造成性能上的负担,因为每个元素都需要绑定事件处理程序。

而使用事件委托的方式,则是将点击事件处理程序绑定到 ul 元素上,然后利用事件冒泡机制,当 li 元素被点击时,事件会冒泡到 ul 元素,并触发 ul 元素上的事件处理程序。这样只需要绑定一个事件处理程序,不论有多少个 li 元素,都能够被正确处理。这样不仅代码更加简洁,而且性能更好,因为减少了大量的事件绑定操作。

总结

优点

  1. 性能优化: 使用事件委托可以减少DOM操作,特别是在有大量子元素需要绑定事件的情况下。通过将事件处理程序绑定到父元素上,而不是每个子元素上,可以大大减少内存消耗和页面加载时间,从而提高性能。
  2. 动态元素支持: 当页面中的元素是动态生成的(例如通过JavaScript添加或移除元素),使用事件委托可以确保新添加的元素也能够享受到相同的事件处理程序,而无需重新绑定事件。
  3. 简化代码: 事件委托使得代码更加简洁和易于维护。通过将事件处理程序绑定到父元素上,而不是分别绑定到每个子元素上,可以减少重复代码,提高代码的可读性和可维护性。
  4. 事件动态性: 通过委托事件,可以动态地修改和调整事件处理逻辑,而无需修改已经绑定的事件处理程序。这使得代码更加灵活和易于调整。

特定场景

尽管事件委托在许多情况下都是一个非常有用的技术,但在某些情况下可能并不适合使用事件委托:

  1. 处理个别事件逻辑: 如果你需要为不同的子元素绑定不同的事件处理逻辑,而不是一致地处理相同类型的事件,那么事件委托可能不是最佳选择。在这种情况下,直接将事件处理程序绑定到每个子元素上可能更为合适。
  2. 性能受限场景: 在某些情况下,虽然事件委托可以减少事件处理程序的数量,但如果父元素本身包含大量的子元素,那么在父元素上处理所有子元素的事件可能会影响性能。在这种情况下,直接在子元素上绑定事件处理程序可能更为合适。
  3. 事件冒泡受限场景: 如果某个父元素或祖先元素对事件冒泡进行了阻止(通过调用 event.stopPropagation()),那么事件委托可能无法正常工作。因为事件不会继续冒泡到父元素,父元素上的事件处理程序也不会被触发。
  4. 特定的DOM结构: 在某些DOM结构下,使用事件委托可能会变得复杂或者不够灵活。例如,如果父元素和子元素之间有多层嵌套,或者事件目标元素位于DOM树的深层结构中,那么使用事件委托可能会导致事件处理逻辑变得复杂。

拓展

在 JavaScript 中,event 是一个表示事件的对象。当事件(比如点击、鼠标移动等)在网页上发生时,浏览器会创建一个事件对象,其中包含了与该事件相关的信息,例如事件类型、触发事件的元素、事件发生的位置等。

event 对象在事件处理函数中非常有用,可以用于:

  1. 获取事件相关的信息: 可以通过 event 对象获取事件的类型(type)、触发事件的目标元素(target)、鼠标位置(clientXclientY)、键盘按键(keyCodekey)等。
  2. 阻止事件默认行为: 可以调用 event.preventDefault() 方法来阻止事件的默认行为,例如阻止链接跳转、表单提交等。
  3. 停止事件传播: 可以调用 event.stopPropagation() 方法来停止事件的传播,防止事件冒泡到父元素或其他元素。
  4. 事件委托: 可以利用事件对象来实现事件委托,通过检查事件目标元素(event.target)来确定哪个元素触发了事件,从而执行相应的操作。
  5. 动态绑定事件处理程序: 可以通过事件对象来动态绑定或解绑事件处理程序,例如使用 addEventListener()removeEventListener() 方法。

event.target

在 JavaScript 中,target 是事件对象(event)的一个属性,表示触发事件的目标元素。当一个事件在网页上发生时,浏览器会创建一个事件对象,其中包含了触发事件的相关信息,其中就包括了 target 属性。

target 属性的主要作用是指示触发事件的具体 DOM 元素。通过访问事件对象的 target 属性,可以获取到触发事件的元素,进而对其进行操作或获取相关信息。这在事件处理程序中特别有用,因为可以根据触发事件的目标元素执行相应的操作。

例如,在一个页面中有多个按钮,每个按钮点击时都会触发相同的事件处理程序。可以通过检查事件对象的 target 属性来确定哪个按钮被点击了,然后根据具体的按钮执行相应的操作。这样就可以实现事件委托,从而减少重复的代码,并且使代码更加灵活和易于维护。

在本文中的,事件委托就是用了event.target.tagName来判断哪个标签被点击了

除了使用 tagName 属性来检查事件目标元素的标签名之外,还可以使用其他属性或方法来确定事件目标的特征。以下是一些示例:

  1. 检查元素的类名(className):
<div class="box" id="box1">Box 1</div>
<div class="box" id="box2">Box 2</div>

<script>
document.addEventListener('click', function(event) {
    // 检查点击的是否是具有特定类名的元素
    if (event.target.classList.contains('box')) {
        // 根据具有特定类名的元素执行相应的操作
        console.log(`Clicked on box with id: ${event.target.id}`);
    }
});
</script>

  1. 检查元素的属性值(getAttribute):
<button data-action="save">Save</button>
<button data-action="delete">Delete</button>

<script>
document.addEventListener('click', function(event) {
    // 检查点击的元素是否具有特定的自定义属性值
    if (event.target.getAttribute('data-action') === 'save') {
        console.log('Save button clicked');
    } else if (event.target.getAttribute('data-action') === 'delete') {
        console.log('Delete button clicked');
    }
});
</script>
  1. 检查元素的父级元素(parentNode):
<ul id="parent">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>

<script>
document.getElementById('parent').addEventListener('click', function(event) {
    // 检查点击的元素是否是父元素的子元素
    if (event.target.parentNode === this) {
        console.log(`Clicked on list item: ${event.target.textContent}`);
    }
});
</script>

当然,target下还有个最为常用的属性value

target.value

value 属性通常用于表单元素(如输入框、下拉框等),它表示元素当前的值。在事件处理程序中,可以使用 value 属性来获取或设置元素的值,以便对用户的输入进行处理或反馈。

  1. 文本框的值
    在这个示例中,当文本框的值发生变化时(用户输入文字),事件处理程序会获取当前文本框的值,并打印到控制台上。
<input type="text" id="inputField" value="Hello">

<script>
document.getElementById('inputField').addEventListener('input', function(event) {
    // 获取文本框的当前值
    const value = event.target.value;
    console.log(`Current value: ${value}`);
});
</script>
  1. 复选框的状态
    在这个示例中,当复选框的选中状态发生变化时,事件处理程序会获取当前复选框的选中状态,并打印到控制台上。
<input type="checkbox" id="checkbox">

<script>
document.getElementById('checkbox').addEventListener('change', function(event) {
    // 获取复选框的当前选中状态
    const isChecked = event.target.checked;
    console.log(`Checkbox checked: ${isChecked}`);
});
</script>
  1. 下拉框的选项
    在这个示例中,当下拉框的选项发生变化时,事件处理程序会获取当前选中的选项的值,并打印到控制台上。
<select id="select">
    <option value="apple">Apple</option>
    <option value="banana">Banana</option>
    <option value="orange">Orange</option>
</select>

<script>
document.getElementById('select').addEventListener('change', function(event) {
    // 获取下拉框当前选中的值
    const selectedValue = event.target.value;
    console.log(`Selected value: ${selectedValue}`);
});
</script>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值