DOM事件流与事件委托
来源:互联网 发布:淘宝怎么差评改好评 编辑:程序博客网 时间:2024/05/18 03:04
- DOM事件流
关于事件流的理解,《js高级三》中有个恰当比喻:
可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上所有的圆。…>换句话说,在单击按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面。
DOM2级事件中规定事件流包含3个阶段:事件捕获阶段、处于目标阶段、冒泡阶段
首先发生的是事件捕获阶段,此时事件还没有传递到目标节点对象上,所以我们就有机会在这个阶段进行事件的截。然后是目标节点接收到事件,最后是事件冒泡阶段,可以在这个阶段对事件做出处理和响应。我们先定义一段简单的html结构:
<!DOCTYPE html><html> <head> <meta charset="utf-8"> </head> <body> <div class="box"> <button type="button" name="button">click me</button> </div> </body></html>
- 事件捕获阶段
在事件捕获阶段中,先由不具体的节点(即上层节点)接收到事件,然后一级一级往下传递,直到最具体的目标节点接收到事件。
在DOM2级事件规范中,要求事件从document对象开始传递,但是诸如Chrome,Firefox等主流浏览器却是从window开始传递的
addEventListener方法的第三个参数是一个布尔值(可选),指定事件处理程序是否在捕获或冒泡阶段执行。 当为true时,则事件处理程序将在捕获阶段执行。
误区:无论addEventListener的第三个参数是否为true,三个阶段都会走一遍,这里的第三个参数,指的是处理程序将会在捕获或者冒泡阶段执行,
document.querySelector('#btn').addEventListener('click', function () { console.log("btn was clicked");},true);document.querySelector('body').addEventListener('click', function () { console.log("body was clicked");},true);document.querySelector('.box').addEventListener('click', function () { console.log("box was clicked");},true);document.addEventListener('click', function () { console.log("document was clicked");},true);window.addEventListener('click', function () { console.log("window was clicked");},true);
点击click me按钮后,控制台依次打印出执行结果:
window was clickeddocument was clickedbody was clickedbox was clikcedbtn was clicked
很明显可以看出,在捕获阶段,事件由window对象开始,从上到下一级一级地向下传递,直到传递到最具体的button对象上
- 事件冒泡阶段
事件冒泡阶段与捕获阶段恰好相反,冒泡阶段是从最具体的目标对象开始,一层一层地向上传递,直到window对象。
addEventListener方法默认就是从冒泡阶段执行事件处理程序。
document.querySelector('#btn').addEventListener('click', function () { console.log("btn was clicked");});document.querySelector('body').addEventListener('click', function () { console.log("body was clicked");});document.querySelector('.box').addEventListener('click', function () { console.log("box was clicked");});document.addEventListener('click', function () { console.log("document was clicked");});window.addEventListener('click', function () { console.log("window was clicked");});
点击click me按钮后,控制台依次打印出执行结果:
btn was clickedbox was clikcedbody was clickeddocument was clickedwindow was clicked
上述过程示意图:
4. 组织事件冒泡
我们可以使用event.stopPropagation()方法阻止事件冒泡过程,以防止事件冒泡而带来不必要的错误和困扰。
示例:
document.querySelector('#btn').addEventListener('click', function (event) { console.log("btn was clicked"); event.stopPropagation();});document.querySelector('body').addEventListener('click', function () { console.log("body was clicked");});document.querySelector('.box').addEventListener('click', function () { console.log("box was clicked");});document.addEventListener('click', function () { console.log("document was clicked");});window.addEventListener('click', function () { console.log("window was clicked");});
点击click me按钮后,控制台打印出执行结果显示,事件没有再向上冒泡传递给其他节点对象:
btn was clicked
事件委托
每个函数都是对象,都会占用内存,所以当我们的页面中所包含的事件数量较多时,如果给每个节点绑定一个事件,加上事件处理程序,就会造成性能很差。还有一个问题是,某个元素节点是后来通过JavaScript动态添加进页面中的,这时候我们如果提前对它进行绑定,但此时该元素并不存在,所以会绑定事件会失败。解决上述两个问题的一个常用方案,就是使用事件委托举个例子:向一个已存在的无序列表ul中动态添加300个子节点li,每个子节点的内容为插入顺序,第一个插入,内容就为1,以此类推,为每个li添加监听事件,点击li,弹出其内容值
//通过id获取无序列表ulvar ndContainer = document.getElementById('js-list'); if (!ndContainer) { return; } for (let i = 0; i < 300; i++) { const ndItem = document.createElement('li'); ndItem.innerText = i + 1; ndContainer.appendChild(ndItem); } //在父节点上添加监听事件 ndContainer.addEventListener('click', function (e) { const target = e.target; if (target.tagName === 'LI') { alert(target.innerHTML); } });
- DOM事件流与事件委托
- 事件流与事件委托
- 面试题-冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件
- js 捕获型事件、冒泡型事件、DOM事件流、事件委托
- 事件绑定与事件委托
- 事件冒泡与事件委托
- 委托入门-事件与委托
- 事件委托、事件触发与事件冒泡
- 事件冒泡、事件捕获与事件委托
- 委托与事件
- 委托与事件
- c# 委托与事件
- 委托与事件
- 事件与委托详解
- 委托与事件详解
- 委托与事件详解
- 委托与事件
- C#委托与事件
- 用PHP实现一个关于德州扑克算法的程序(四):代码
- Android提示BOM错误排查
- Ubuntu shadowsocks https_proxy
- 文章标题
- 全局设置、自定义BuildConfig
- DOM事件流与事件委托
- android EditText 只允许输入指定字符
- 学生信息的添加与查询
- ScratchCardView:刮刮卡视图组件
- redis运维常用命令
- Gradle for Android 第四篇( 构建变体 )
- C#学习之as是什么意思?
- Tree UVA
- 前端构建工具gulpjs的使用介绍及技巧