-
今天来聊⼀聊事件的执⾏机制
结合上次跟大家分享的事件基础,如果还没有看过的童鞋,以下是传送门
【js事件详解】上
-
那么什么是事件的执⾏机制呢?
思考⼀个问题
当⼀个⼤盒⼦嵌套⼀个⼩盒⼦的时候,并且两个盒⼦都有点击事件
你点击⾥⾯的⼩盒⼦,外⾯的⼤盒⼦上的点击事件要不要执⾏?
1. 事件的传播
就像上⾯那个图⽚⼀样,我们点击在红⾊盒⼦身上的同时,也是点击在了粉⾊盒⼦上,这个是既定事实,那么两个盒⼦的点击事件都会触发,这个就叫做事件的传播
- 当元素触发⼀个事件的时候,其⽗元素也会触发相同的事件,⽗元素的⽗元素也会触发相同的事件,就像上⾯的图⽚⼀样
- 点击在红⾊盒⼦上的时候,会触发红⾊盒⼦的点击事件,
- 也是点击在了粉⾊的盒⼦上,也会触发粉⾊盒⼦的点击事件,
- 也是点击在了 body 上,也会触发 body 的点击事件,
- 也是点击在了 html 上,也会触发 html 的点击事件,
- 也是点击在了 document 上,也会触发 document 的点击事件,
- 也是点击在了 window 上,也会触发 window 的点击事件,
- 也就是说,⻚⾯上任何⼀个元素触发事件,都会⼀层⼀层最终导致 window的相同事件触发,前提是各层级元素得有注册相同的事件,不然不会触发
-
在事件传播的过程中,有⼀些需要去注意的点:
1.只会传播同类事件 2.只会从点击元素开始按照 html 的结构逐层向上元素的事件会被触发 3.内部元素不管有没有该事件,只要上层元素有该事件,那么上层元素的事件就会被触发
-
到现在,我们已经了解了事件的传播,我们再来思考⼀个问题
-事件确实会从⾃⼰开始,到window的所有相同事件都会触发,是因为我们点在⾃⼰身上,也确实逐层的点在了直⾄window的每⼀个元素身上 -但是到底是先点在⾃⼰身上,还是先点在了window身上呢? -先点在⾃⼰身上,就是先执⾏⾃⼰的事件处理函数,逐层向上最后执⾏window的事件处理函数 -反之,则是先执⾏ window 的事件处理函数,逐层向下最后执⾏⾃⼰身上的事件处理函数
2. 冒泡、捕获、⽬标
- 我们刚才聊过了,每⼀个事件,都是有可能从⾃⼰到 window ,有可能要执⾏多个同类型事件。
- 那么这个执⾏的顺序就有⼀些说法了。
⽬标
- 你是点击在哪个元素身上了,那么这个事件的⽬标就是什么。
冒泡和捕获
事件流
- 事件流是描述的从⻚⾯接受事件的顺序,当⼏个都具有事件的元素层叠在⼀起的时候,那么你点击其中⼀个元素,并不是只有当前被点击的元素会触发事件,⽽层叠在你点击范围的所有元素都会触发事件。事件流包括两种模式:冒泡和捕获。
事件冒泡
- 就是从事件 ⽬标 的事件处理函数开始,依次向外,直到 window 的事件处理函数触发,也就是从下向上的执⾏事件处理函数
事件捕获
- 就是从 window 的事件处理函数开始,依次向内,只要事件 ⽬标 的事件处理函数执⾏,也就是从上向下的执⾏事件处理函数
冒泡和捕获的区别
- 就是在事件的传播中,多个同类型事件处理函数的执⾏顺序不同
3. 阻⽌事件传播(冒泡和捕获)
3.1 事件触发(⽬标)对象及兼容
cancelBubble=true IE写法
stopPropagation() 其他浏览器
3.2 ⽬标对象/触发对象
事件对象.target || window.event.srcElement;
【注】事件是由谁⽽起。
4. 事件委托
-
就是把我要做的事情委托给别⼈来做
-
因为我们的冒泡机制,点击⼦元素的时候,也会同步触发⽗元素的相同事件
-
所以我们就可以把⼦元素的事件委托给⽗元素来做
好处:
1、节省资源同时减少了dom操作,提⾼性能
2、对于新添加的元素也会有之前的事件
4.1 事件触发
- 点击⼦元素的时候,不管⼦元素有没有点击事件,只要⽗元素有点击事件,那么就可以触发⽗元素的点击事件
<script>
var oUl = docuemnt.querySelector('ul')
oUl.addEventListener('click', function (e) {
console.log('我是 ul 的点击事件,我被触发了')
})
</script>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
像上⾯⼀段代码,当你点击ul的时候肯定会触发
但是当你点击li的时候,其实也会触发
4.2 target
- target 这个属性是事件对象⾥⾯的属性,表示你点击的⽬标
- 当你触发点击事件的时候,==你点击在哪个元素上,target就是哪个元素 ==
- 这个target也不兼容,在 IE下要使⽤srcElement
<script>
var oUl = docuemnt.querySelector('ul')
oUl.addEventListener('click', function (e) {
e = e || window.event
var target = e.target || e.srcElement
console.log(target)
})
</script>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
上⾯的代码,当你点击ul的时候,target就是ul
当你点击在 li 上⾯的时候,target就是 li
4.3 委托
- 这个时候,当我们点击 li的时候,也可以触发ul的点事件
- 并且在事件内部,我们也可以拿到你点击的到底是ul还是li
- 这个时候,我们就可以把 li 的事件委托给 ul 来做
<script>
var oUl = docuemnt.querySelector('ul')
oUl.addEventListener('click', function (e) {
e = e || window.event
var target = e.target || e.srcElement
// 判断你点击的是 li
if (target.nodeName.toUpperCase === 'LI') {
// 确定点击的是 li
// 因为当你点击在 ul 上⾯的时候,nodeName 应该是 'UL'
// 去做点击 li 的时候该做的事情了
console.log('我是 li,我被点击了')
}
})
</script>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
上⾯的代码,我们就可以把 li 要做的事情委托给 ul 来做
5. 默认⾏为
- 默认⾏为,就是不⽤我们注册,它⾃⼰就存在的事情
- ⽐如我们点击⿏标右键的时候,会⾃动弹出⼀个菜单
- ⽐如我们点击a标签的时候,我们不需要注册点击事件,他⾃⼰就会跳转⻚⾯
- 这些不需要我们注册就能实现的事情,我们叫做默认事件
5.1 阻⽌默认⾏为
有的时候,我们不希望浏览器执⾏默认事件
- ⽐如我给 a 标签绑定了⼀个点击事件,我点击你的时候希望你能告诉我你的地址是什么
- ⽽不是直接跳转链接
- 那么我们就要把a标签原先的默认事件阻⽌,不让他执⾏默认事件
我们有两个⽅法来阻⽌默认事件
e.preventDefault() : ⾮ IE 使⽤
e.returnValue = false :IE 使⽤
我们阻⽌默认事件的时候也要写⼀个兼容的写法
<a href="https://www.baidu.com">点击我试试</a>
<script>
var oA = document.querySelector('a')
a.addEventListener('click', function (e) {
e = e || window.event
console.log(this.href)
e.preventDefault ? e.preventDefault() : e.returnValue =false;
})
</script>
这样写完以后,你点击 a 标签的时候,就不会跳转链接了
⽽是会在控制台打印出 a 标签的 href 属性的值
总结:
-
为什么要⽤事件委托?
我⻚⾯上本身没有 li 我通过代码添加了⼀些 li,但是添加进来的 li 是没有点击事件的 我每次动态的操作完 li 以后都要从新给li绑定⼀次点击事件⽐较麻烦 这个时候只要委托给 ul 就可以了 因为新加进来的 li 也是 ul 的⼦元素,点击的时候也可以触发ul的点击事件
-
事件委托的书写
元素的事件只能委托给结构⽗级或者再结构⽗级的同样的事件上 li 的点击事件,就不能委托给 ul 的⿏标移⼊事件 li的点击事件,只能委托给 ul 或者在⾼⽗级的点击事件上
【重点】好了以上就是JS事件详解的所有内容,以后还会对js事件有所补充,感兴趣的朋友们可以点赞关注走一波。