【前置知识】
- 事件捕获
- 事件冒泡
什么是事件委托
捕获和冒泡允许我们实现一种被称为 事件委托 的强大的事件处理模式。
思路
如果我们有许多以类似方式处理的元素,那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上。
如图
该表格有9个格子,想要实现点击时高亮显示被点击的单元格 。
代码大概如下
<table>
<tr>
<td class="a1">1</td>
<td class="a2">2</td>
<td class="a3">3</td>
</tr>
<tr>
<td class="a4">4</td>
<td class="a5">5</td>
<td class="a6">6</td>
</tr>
<tr>
<td class="a7">7</td>
<td class="a8">8</td>
<td class="a9">9</td>
</tr>
</table>
效率低下的做法: 为每个 <td>
(可能更多)分配一个 onclick
~~
事件委托做法:直接在 <table>
设置一个“捕获所有”的处理程序。
let selectedTd;
let table = document.getElementsByTagName('table');
let highlight = (td) => {
if(selectedTd) {// 移除现有的高亮显示,如果有的话
selectedTd.classList.remove('highlight')
}
selectedTd = td;
selectedTd.classList.add('highlight');
}
table.onclick = (event) => {
let target = event.target; //在哪里点击?
if(target.tagName != 'TD') return;
highlight(target)
}
什么是事件委托
- 事件委托指的是不在事件的发生地(直接DOM)上设置监听函数,而是在其父元素上设置监听函数。
- 通过事件冒泡,父元素可以监听到被触发的子元素事件,通过判断事件发生元素DOM的类型,来作出不同的响应。
- 当子元素有很多时,使用事件委托可以避免对特定的每个节点添加事件监听器,事件监听被添加到它们的父元素上,事件监听函数这是可以从子元素上冒泡上来的事件,找到是哪个子元素事件。
怎么阻止默认动作
默认动作指的是什么?
默认动作指的是浏览器自己的行为。
例如:
- 点击
<a href="#">
的时候浏览器自动跳转到指定页面。 - 滚动鼠标时页面会向下滚动,但我们按空格键和按方向键时页面也会向下滚动。
- 等等
有时候有一些需求,为了更好的用户体验,需要阻止浏览器本身的默认行动。
办法
有两种方式:
- 主流的方法是使用
event
对象,有一个event.preventDefault()
方法。 - 如果处理程序是使用
on<event>
(而不是addEventListener
)分配的,那返回false
也同样有效。
<a href="/" onclick="return false">Click here</a>
//or
<a href="/" onclick="event.preventDefault()">Click here</a>
怎么阻止事件冒泡
例子:
<div class="爷爷">
<div class="爸爸">
<div class="儿子">
文字
</div>
</div>
</div>
如上代码,假如我分别给爷爷、爸爸、儿子绑定 fnYe
、 fnBa
、 fnEr
三种点击事件。
- 如果我没有阻止默认事件,则默认会按下面执行:
- 当我点击
文字
时,就会按照事件捕获从Window
—>Document
—><html>
—><body>
—><div class="爷爷">
—><div class="爸爸">
—><div class="儿子">
寻找是否有监听。 - 然后,就会按照冒泡事件从
<div class="儿子">
一直到Window
的过程寻找是否有监听,并依次执行监听,事件捕获是相反的。
:::info
趣事:
IE5支持事件冒泡,而网景支持事件捕获。因为意见不合这两家公司闹到w3c。然后为了让这两家公司觉得公平,就规定浏览器应该同时支持两种调用顺序。
:::
如何阻止事件冒泡?
冒泡事件如同冒泡一样,从底部上升到水面,这个上升的过程还会依次执行代码,例如上面的儿子爸爸爷爷的代码,如图
默认情况下,当我点击 儿子
时,就会依次执行fuer
、 fuba
和fuye
,
如果我只想执行 fuer
,不想执行 后面的fuba
和 fuye
,就需要阻止冒泡事件。
两种方法:
event.stopPropagation(); //W3C
//or
event.cancelBubble = true; //IE
虽然不太可能遇到,但如果需要兼容IE,可以这样:
if (document.all) {
// IE
event.cancelBubble = true;
} else {
event.stopPropagation();
}
【资料来源】 事件委托—-javascript.info 冒泡和捕获—-JavaScript.info 浏览器默认行为—-JavaScript.info