一, 前言
熟悉了 vue 的指令系统后, 在实际开发中, 不可避免的会使用到对于事件的操作, 如何处理 DOM 事件流, 成为我们必须要掌握的技能. 不同于传统的前端开发, 在 Vue 中给我们提供了事件修饰符这一利器, 使我们可以便捷的处理 DOM 事件, 本章, 一起来学习如何使用事件修饰符来实现对于 DOM 事件流的操作.
学习系列目录地址: https://www.cnblogs.com/danvic712/p/9549100.html
仓储地址:
二, 干货合集
1, DOM 事件流
有时, 当我们需要完成页面中的某些功能时, 我们要在需要实现功能的页面元素上使用 v-on 指令去监听 DOM 事件, 在 html4 时代浏览器如何确定页面的哪一部分会拥有特定的事件时, IE 和 Netscape 的开发团队提出了两个截然相反的概念. 这一差异, 也使我们在写代码中需要考虑如何去处理 DOM 的事件细节. 为了解决这一问题, vue 给我们提供了事件修饰符这一利器, 它使我们的方法只有纯粹的数据逻辑, 而不是去处理 DOM 事件细节.
一些涉及到概念:
a) 事件: 用户设定或者是浏览器自身执行的某种动作. 例如 click(点击),load(加载),mouseover(鼠标悬停),change(改变) 等等
b) 事件处理程序: 为了实现某个事件的功能而构建的函数方法, 也可称为事件监听器
c)DOM 事件流: 描述的是从页面中接收事件的顺序, 也可理解为事件在页面中传播的顺序
在 DOM 事件流中存在着三个阶段: 事件捕获阶段, 处于目标阶段, 事件冒泡阶段.
a) 事件捕获 (event capture): 当鼠标点击或者触发 DOM 事件时, 浏览器会从根节点开始由外到内进行事件传播, 即点击了子元素, 如果父元素通过事件捕获方式注册了对应的事件的话, 会先触发父元素绑定的事件
b) 事件冒泡 (event bubbing): 当鼠标点击或者触发 DOM 事件时, 浏览器会从根节点开始由内到外进行事件传播, 即点击了子元素, 则先触发子元素绑定的事件, 逐步扩散到父元素绑定的事件
之前我们提到的 IE 和 Netscape 的开发团队提出了两个截然相反的事件流概念, IE 采取的是事件冒泡流, 而标准的浏览器的事件流则是事件捕获流. 所以, 为了兼容 IE 我们需要改变某些的写法.
2, 事件修饰符
a).stop: 阻止事件冒泡
在下面的示例中, 我们分别创建了一个 button 的点击事件和外侧的 div 的点击事件, 根据事件的冒泡机制我们可以得知, 当我们点击了按钮之后, 会扩散到父元素, 从而触发父元素的点击事件, 具体的结果也如下图所示:
- <div id="app" class="divDefault">
- <div id="div1" @click="divHandlerClick">
- <input type="button" value="点击" @click="btnHandlerClick" />
- </div>
- </div>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {},
- methods: {
- divHandlerClick() {
- alert('我是 div 的点击事件!')
- },
- btnHandlerClick() {
- alert('我是 button 的点击事件')
- }
- }
- });
- </script>
这时候, 如果我们不希望出现事件冒泡, 则可以使用 Vue 内置的修饰符便捷的阻止事件冒泡的产生. 因为我们是点击 button 后产生的事件冒泡, 我们只需要在 button 的点击事件上加上 stop 修饰符即可, 示例代码如下.
<input type="button" value="点击" @click.stop="btnHandlerClick" />
b).prevent: 阻止默认事件
阻止默认事件这个也很好理解, 有些标签本身会存在事件, 例如, a 标签的跳转, form 表单中 submit 按钮的提交事件等等, 在某些时候我们只想执行我们自己设置的事件, 这时, 就需要阻止标签的默认事件的执行, 原生的 JS 我们可以使用 preventDefault 方法来实现, 而在 Vue 中, 我们只需要使用 prevent 关键字就可以了.
在下面的示例中, 我们为 a 标签添加了一个点击事件, 由于 a 标签本身具有默认的跳转事件, 此时, 当我们点击后, 最终还是会执行 a 标签的默认事件.
- <a href="http://www.baidu.com" @click="aHandlerClick"> 链接跳转 </a>
- <script>
- var vm = new Vue({
- el: '#app',
- data: {},
- methods: {
- aHandlerClick() {
- alert('我是 a 标签的点击事件')
- }
- }
- });
- </script>
在 Vue 中, 当我们想要阻止元素的默认事件, 只需要在绑定的事件后使用 prevent 修饰符即可, 示例代码如下.
<a href="http://www.baidu.com" @click.prevent="aHandlerClick"> 链接跳转 </a>
c).capture: 添加事件监听器时使用事件捕获模式
在上面的学习中我们了解到, 事件捕获模式与事件冒泡模式是一对相反的事件处理流程, 当我们想要将页面元素的事件流改为事件捕获模式时, 只需要在父级元素的事件上使用 capture 修饰符即可, 还是上面的例子的代码, 当我们在 div 绑定的点击事件上使用 capture 修饰符后, 我们点击按钮首先触发的就是最外侧的 div 的事件.
- <div id="app" class="divDefault">
- <div id="div1" @click.capure="divHandlerClick">
- <input type="button" value="点击" @click="btnHandlerClick" />
- </div>
- </div>
d).self: 只当在 event.target 是当前元素自身时触发处理函数 (比如不是子元素冒泡引起的事件触发)
在上面的例子中, 我们为 div 绑定了一个点击事件, 而我们的本意可能是只有当我们点击 div 后触发这个事件, 而实际情况是事件冒泡还是事件捕获都会触发这个事件, 这与我们的本意是不符的. 在 Vue 中, 我们就可以使用 self 修饰符去修饰事件, 让这个事件只在我们想要触发时触发.
- <div id="app" class="divDefault">
- <div id="div1" @click.self="divHandlerClick">
- <input type="button" value="点击" @click="btnHandlerClick" />
- </div>
- </div>
e).once: 事件只触发一次
当我们仅仅想对绑定的事件只在第一次的时候触发, 这时我们就可以使用 once 修饰符去修饰绑定的事件. 例如在下面的代码中, 只有第一次点击时才会触发绑定的事件, 之后点击都不会触发.
<input type="button" value="点击" @click.once="btnHandlerClick" />
f).passive: 滚动事件的默认行为 (即滚动行为) 将会立即触发
在页面滚动的时候, 浏览器会在整个事件处理完毕之后再触发滚动, 因为浏览器并不知道这个事件是否在其处理函数中被调用了 event.preventDefault(), 而 passive 修饰符用来进一步告诉浏览器这个事件的默认行为不会被取消, 即 使用 passive 修饰符后表示绑定的事件永远不会调用 event.preventDefault().
三, 总结
1, 事件修饰符的使用顺序很重要
使用修饰符时, 顺序很重要; 相应的代码会以同样的顺序产生. 因此, 用 v-on:click.prevent.self 会阻止所有的点击, 而 v-on:click.self.prevent 只会阻止对元素自身的点击.
2,.passive 和 .prevent 不能一起使用
不要把 .passive 和 .prevent 一起使用, 因为 .prevent 将会被忽略, 同时浏览器可能会向你展示一个警告. 请记住,.passive 会告诉浏览器你不想阻止事件的默认行为.
四, 参考
1,JavaScript 事件流
2,JavaScript: 深入理解事件流 https://segmentfault.com/a/1190000003497939
3, 理解 DOM 事件流的三个阶段 https://segmentfault.com/a/1190000004463384
4,JavaScript 详说事件机制之冒泡, 捕获, 传播, 委托 https://segmentfault.com/a/1190000004463384
5,vue 从入门到进阶: 指令与事件 (二)
来源: https://www.cnblogs.com/danvic712/p/9846097.html