JS中的事件委托(事件代理)

本文深入讲解事件委托(事件代理)的概念及其在JavaScript中的应用。通过对比传统事件绑定方法,阐述事件委托如何提高代码效率和简化动态元素事件处理,附带实例代码说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一步一步来说说事件委托(或者有的资料叫事件代理)

  1. js中事件冒泡我们知道,子元素身上的事件会冒泡到父元素身上。
  2. 事件代理就是,本来加在子元素身上的事件,加在了其父级身上。
  3. 那就产生了问题:父级那么多子元素,怎么区分事件本应该是哪个子元素的?
  4. 答案是:event对象里记录的有“事件源”,它就是发生事件的子元素。
  5. 它存在兼容性问题,在老的IE下,事件源是 window.event.srcElement,其他浏览器是 event.target
  6. 用事件委托有什么好处呢?
  7. 第一个好处是效率高,比如,不用for循环为子元素添加事件了
  8. 第二个好处是,js新生成的子元素也不用新为其添加事件了,程序逻辑上比较方便

--------------------

好吧,下面还是用例子来说,更容易理解。

---------------------

例子1. 页面有个ul包含着4个li,鼠标移动到li上,li背景变成红色,移出,背景恢复原色。

如果按照以前的写法,代码如下:

 

 1         <ul id="ul1">
 2             <li>111</li>
 3             <li>222</li>
 4             <li>333</li>
 5             <li>444</li>
 6         </ul>
 7         
 8         <script type="text/javascript">
 9             window.onload = function(){
10                 var oUl = document.getElementById('ul1');
11                 var aLi = oUl.children;
12                 console.log(aLi);
13                 
14                 //传统方法,li身上添加事件,需要用for循环,找到每个li
15                 for (var i=0;i<aLi.length;i++) {
16                     aLi[i].onmouseover = function() {
17                         this.style.background = 'red';
18                     }
19                     aLi[i].onmouseout = function(){
20                         this.style.background = '';
21                     }
22                 }//for结束
23 
24                 
25             }
26         </script>

 

现在用事件委托的方式,onmouseover、onmouseout方法要加在ul身上了,再通过找事件源的方式,改变li背景,代码如下:

 上面ul的html代码不变,js部分变为

 1 <script type="text/javascript">
 2             window.onload = function(){
 3                 var oUl = document.getElementById('ul1');                
 4                 oUl.onmouseover = function(ev){
 5                     var ev = ev || window.event;
 6                     var oLi = ev.srcElement || ev.target;
 7                     oLi.style.background = 'red';                    
 8                 }
 9                 
10                 oUl.onmouseout = function(ev){
11                     var ev = ev || window.event;
12                     var oLi = ev.srcElement || ev.target;
13                     oLi.style.background = '';                    
14                 }
15                 
16             }
17         </script>

 

效果如下:

 

但是会发现,鼠标移到了ul身上而不是某个li身上时,获取的事件源是ul,那么整个ul背景将变红,这不是想要的结果,怎么办?

答曰:加个判断。通过事件源的nodeName判断是不是li,是才做出反应,不是不理它。为了防止nodeName在不同浏览器获取的字母大小写不同,加个toLowerCase()

所以,上面的js代码更改如下:

 1         <script type="text/javascript">
 2             window.onload = function(){
 3                 var oUl = document.getElementById('ul1');
 4                 
 5                 oUl.onmouseover = function(ev){
 6                     var ev = ev || window.event;
 7                     var oLi = ev.srcElement || ev.target;
 8                     if(oLi.nodeName.toLowerCase() == 'li'){
 9                         oLi.style.background = 'red';
10                     }
11                                         
12                 }
13                 
14                 oUl.onmouseout = function(ev){
15                     var ev = ev || window.event;
16                     var oLi = ev.srcElement || ev.target;
17                     if(oLi.nodeName.toLowerCase() == 'li'){
18                         oLi.style.background = '';
19                     }                
20                 }
21 
22                 
23             }
24         </script>
25         

 

效果如下很完美:

这就是不用for循环写一堆了,下面再来说说第二个好处:js新生成的子元素也不用新为其添加事件了,程序逻辑上比较方便

上面的文件,假如我再新添加个按钮,点击按钮,ul里就新增加个li,如果用传统的方法,for循环为li添加事件,问题就出现了,最开始有的4个li是有onmouseover和onmouseout事件的,但是后来动态生成的li里没有这两个事件处理函数,因为for循环的时候它还没生成。怎么办呢?只能在按钮点击后,生成li,然后再为生成的li再绑定事件,真是麻烦的很。而事件委托的方式就没事,当后来动态生成的li出现的时候,不用做改变,移到它身上,还是变色的,因为事件是绑定在ul身上的。

新浪微博里,当你发一条新微博出去,发出去的信息在页面上显示,鼠标移动到新发的信息的人头像上时,依然会有很多事件,如果用原来的方式,就要做很多处理,事件委托的话,就很方便了!

 

转载于:https://www.cnblogs.com/html55/p/10164914.html

### 事件代理事件委托)的原理 事件代理事件委托)的核心原理是利用 **事件冒泡机制**。在DOM树中,事件会从最内层的元素开始触发,并逐层向上传播到父元素。例如,如果一个 `<a>` 标签嵌套在 `<li>` 中,而 `<li>` 又嵌套在 `<ul>` 里,那么点击 `<a>` 元素时,事件会依次冒泡到 `<li>` 和 `<ul>` 上。 基于这一特性,可以将事件监听器绑定在父元素上,而不是为每个子元素单独绑定。这样,父元素就可以统一处理子元素的事件。例如,点击某个 `<li>` 元素时,可以在 `<ul>` 上监听事件并进行处理,而不需要为每个 `<li>` 添加单独的监听器 [^4]。 ### 事件委托的优势 1. **减少事件监听器数量**:通过将事件监听器绑定到父元素,可以显著减少页面上的事件监听器数量,从而优化内存使用和性能 [^2]。 2. **支持动态元素绑定**:即使子元素是动态添加的,事件仍然可以通过父元素正确触发,无需重新绑定事件 [^3]。 3. **提高代码可维护性**:统一的事件管理使得代码更简洁,更容易维护 [^1]。 ### 事件委托的使用方法 #### 基本实现 以下是一个简单的示例,展示如何通过事件委托来减少事件监听器的数量: ```html <ul id="ul"> <li>111</li> <li>222</li> <li>333</li> <li>444</li> <li>555</li> <li>666</li> </ul> ``` ```javascript window.onload = function () { var myul = document.getElementById('ul'); myul.addEventListener('click', function (event) { // 检查事件目标是否是 li 元素 if (event.target && event.target.nodeName === 'LI') { console.log('点击了 li 元素'); } }); }; ``` 在这个示例中,`<ul>` 元素监听了所有点击事件,并通过 `event.target` 来判断点击的是不是 `<li>` 元素。这种方式避免了为每个 `<li>` 绑定单独的点击事件 [^4]。 #### 动态元素支持 如果 `<li>` 是通过 JavaScript 动态添加的,使用事件委托仍然可以正常工作,因为事件最终会冒泡到父元素 `<ul>` 上: ```javascript // 动态添加 li 元素 var newLi = document.createElement('li'); newLi.textContent = '777'; document.getElementById('ul').appendChild(newLi); ``` 添加的 `<li>` 元素同样会触发 `<ul>` 上的点击事件,无需额外绑定 [^2]。 #### 事件对象的使用 在事件处理函数中,可以通过 `event.target` 获取实际触发事件的元素,而 `event.currentTarget` 则指向绑定事件的父元素。这样可以灵活地处理不同子元素的交互逻辑: ```javascript myul.addEventListener('click', function (event) { if (event.target && event.target.classList.contains('special')) { console.log('点击了具有 special 类的元素'); } }); ``` #### 阻止默认行为和冒泡 在某些情况下,可能需要阻止事件的默认行为或阻止事件冒泡。可以通过 `event.preventDefault()` 和 `event.stopPropagation()` 来实现: ```javascript myul.addEventListener('click', function (event) { if (event.target && event.target.nodeName === 'LI') { event.preventDefault(); // 阻止默认行为 event.stopPropagation(); // 阻止事件冒泡 console.log('阻止了默认行为和冒泡'); } }); ``` ### 事件委托的适用场景 1. **大量子元素的交互**:例如表格、列表等,通过事件委托可以减少监听器数量,提升性能 [^3]。 2. **动态内容更新**:当页面内容频繁变化时,事件委托可以确保新增元素自动继承事件处理逻辑 。 3. **统一事件管理**:适用于需要集中管理事件逻辑的场景,例如全局导航菜单、表单验证等 [^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值