事件流
在早期 IE 和 Netscape 团队在开发第四代浏览器的时候,遇到一个问题:当点击一个按钮的时候,是应该先处理父级的事件呢?还是应该先处理按钮的事件呢?IE 和 Netscape 给出了 2 种完全相反的答案,IE 提出事件冒泡的概念,而 Netscape 则支持事件捕获。
事件冒泡
事件冒泡认为事件应该由最具体的元素开始触发,然后层层往父级传播:
事件捕获
而事件捕获则相反,认为最外层的元素应该最先收到事件,然后层层往下级传递:
DOM 事件流
为了在浏览器中兼容这 2 种事件流,在 DOM2 Events 规范中将事件流分为 3 个阶段:事件捕获阶段、到底目标阶段、事件冒泡阶段。
可以通过指定 addEventListener 的第三个参数为 true 来设置事件是在捕获阶段调用事件处理程序,默认是 false 指在冒泡阶段调用事件处理程序。
事件处理程序
HTML 事件处理程序
就是将事件处理程序直接绑定到 HTML 的属性中:
- // 方式一
- <div onclick="console.log('hello world')"></div>
- 方式二
- <div onclick="print(event)"></div>
- <script>
- function print(e) { }
- </script>
HTML 事件处理程序修改事件相对麻烦,可能需要同时修改 HTML 和 JS,所以大家都不爱使用这种方式绑定事件。
DOM0 事件处理程序
将一个函数赋值给 DOM 元素的一个事件处理程序属性,比如 onclick:
- let btn = document.getElementById('div')
- // 添加事件
- btn.onclick = function() { }
- // 移除事件
- btn.onclick = null
DOM2 事件处理程序
通过 addEventListener 可以添加 DOM2 级别的事件处理程序,它接收 3 个参数:事件名、事件处理程序和 useCapture (它是一个可选参数,是个布尔值,默认为 false 表示在冒泡阶段调用事件处理程序)
- let btn = document.getElementById('div')
- btn.addEventListener('click', () => {
- }, false)
和 DOM0 事件处理程序的区别:
它有几个注意事项:
- let btn = document.getElementById('div')
- let handler = function() { }
- btn.addEventListener("click", handler)
- btn.removeEventListener("click", handler)
事件处理函数
由于 addEventListener 无法兼容 IE8 及更早版本,所以此时就可以使用 attachEvent 添加事件处理程序和用 detachEvent 移除事件处理程序。
- let btn = document.getElementById('div')
- btn.attachEvent("onclick", function() { })
它有这么几个注意事项:
attachEvent 和 detachEvent 是 IE 专属的 API,所以如果有兼容性要求,我们可以写出跨浏览器的事件处理程序:
- var EventUtil = {
- addHandler: function(element, type, handler) {
- if (element.addEventListener) {
- element.addEventListener(type, handler, false)
- } else if (element.attachEvent) {
- element.attachEvent("on" + type, handler)
- } else {
- element["on" + type] = handler;
- }
- },
- removeHandler: function(element, type, handler) {
- if (element.removeEventListener) {
- element.removeEventListener(type, handler, false)
- } else if (element.detachEvent) {
- element.detachEvent("on" + type, handler)
- } else {
- element["on" + type] = null
- }
- }
- }
事件对象
通过不同的事件处理程序添加的事件,event 对象的属性略有不同,我们不需要记住他们的差异,只需要在平时写代码的时候养成一个写兼容代码的习惯即可,如下是一个兼容各种 event 对象的事件处理程序:
- let handler = function(event) {
- // 事件对象
- let event = event || window.event
- // 目标元素
- let target = event.target || event.srcElement
- // 阻止默认事件触发
- if (event.preventDefault) {
- event.preventDefault()
- } else {
- event.returnValue = false
- }
- // 阻止事件冒泡
- if (event.stopPropagation) {
- event.stopPropagation()
- } else {
- event.cancelBubble = true
- }
- }
事件类型
DOM3 Events 定义了如下事件类型:
事件委托
事件委托是指将多个元素上绑定的事件通过利用事件冒泡的原理从而转移到他们共同的父级上去绑定,从而在一定程度上起到性能优化的作用,有的人也喜欢叫它事件代理。比如在 Vue中经常会将事件绑定到每个列表项中:
- <ul>
- <li v-for="item in list" :key="item" @click="handleClick(item)">{{item}}</li>
- </ul>
其实更好的做法是利用事件委托,将事件绑定到 ul 上:
- <ul @click="handleClick">
- <li v-for="item in list" :key="item" :data-item="item">{{item}}</li>
- </ul>
- handleClick(event) {
- let target = event.target
- if (target === 'li') {
- let data = target.dataset.item
- }
- }
感谢阅读首先感谢你阅读本文,相信你付出的时间值得拥有这份回报。
正则忽略大小写 – RegexOptions.IgnoreCase 例如: 复制代码 代码如下: Str = R...
错误描述: 在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报...
DELETEFROMTablesWHEREIDNOTIN(SELECTMin(ID)FROMTablesGROUPBYName) Min的话保...
4月11日20:30~22:00通过腾讯会议进行了第二次在线学习讨论我把学习笔记整理一下...
项目中用到的一些特殊字符和图标 html代码 XML/HTML Code 复制内容到剪贴板 div ...
工具:Eclipse,Oracle,smartupload.jar;语言:jsp,Java;数据存储:Oracle。...
复制代码 代码如下: % URL="http://news.163.com/special/00011K6L/rss_newstop....
Elasticsearch 是通过 Lucene 的倒排索引技术实现比关系型数据库更快的过滤。特...
上篇文章给大家介绍了 Java正则表达式匹配,替换,查找,切割的方法 ,接下来,...
本文实例讲述了Laravel框架源码解析之反射的使用。分享给大家供大家参考,具体如...