前言
在学习vue2时,学到了 事件修饰符,但是对事件的默认行为和传播行为不太理解,所以也就是不知道为啥要使用事件修饰符,所以找了一些资料,在此记录一下。
Vue2官方文档
事件处理 — Vue.js (vuejs.org)https://v2.cn.vuejs.org/v2/guide/events.html
事件的默认和传播行为
在 Web 应用程序中,事件处理是非常常见的需求。事件可以是任何用户交互行为,例如单击、双击、拖动、滚动、键盘按键等等。在处理这些事件时,有时需要避免其默认行为和传播行为。下面是对两种行为的简要说明:
事件的默认行为
当用户执行某些操作时(例如单击链接、提交表单或拖动元素),浏览器会根据默认行为来处理这些事件。例如,单击链接将跳转到链接指定的页面,而提交表单将向服务器发送表单数据。这些默认行为通常符合用户期望和习惯,但在某些情况下,我们希望通过 JavaScript 来修改或取消这些默认行为。
调用 event.preventDefault()
可以取消事件的默认行为。
例如,在处理表单时,如果用户没有输入必填项,我们可能希望通过取消表单提交来防止表单被发送到服务器(阻止表单提交的方法有很多种,这只是一种)。
此外,通过 preventDefault()
也可以自定义一些事件处理逻辑,例如在链接上绑定点击事件,并且 href
属性指向一个新的页面,但是在函数内部根据一些条件取消链接的跳转行为。
事件的传播行为
在 Web 应用程序中,事件不仅会发生在目标元素上,还会沿着 DOM 树向上传播。这种传播被称为事件冒泡,如同水中气泡从下往上冒。例如,当用户单击一个按钮时,单击事件将首先触发按钮上的处理程序。如果该处理程序没有调用 stopPropagation()
来停止事件冒泡,则事件将向父元素传播,依此类推,直到文档根节点。
通过在事件处理程序中调用 event.stopPropagation()
可以阻止事件的传播行为。这在某些情况下非常有用,例如在一个嵌套的元素结构中,如果你希望只捕获当前元素的事件而不是其祖先元素中已经注册了相同类型的事件。
如果我们不避免事件的默认行为和传播行为,可能会导致一些不期望的后果。例如,在表单提交时,如果用户未完成必填项,浏览器将自动禁止表单提交,并在表单元素上显示错误提示,但是如果我们取消了默认行为,这个机制就不会生效。同样地,如果我们没有避免事件的传播行为,事件可能会到达意外的元素,导致应用程序不稳定或出现意外行为。
Vue2中的事件修饰符
Vue官方的说法:
在事件处理程序中调用
event.preventDefault()
或event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为
v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
Vue2中的事件修饰符:
-
.prevent:阻止默认事件(常用)
-
.stop:阻止事件冒泡(常用)
-
.once:事件只触发一次(常用)
-
.self:只有event.target=currentTarget是才触发事件(即只有自己才能触发,也可以用来阻止冒泡)
(不常用)
-
.passive:事件的默认行为会立即执行,无需等待事件回调函数执行完毕
-
.capture:使用事件的捕获模式。即内部元素触发的事件先在此处理,然后才交由内部元素进行处理
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
下面是另一个例子,读者可以粘贴到自己VSCode中运行,从而更好地理解。(注意:我这里是将vue框架包vue.js直接复制到了项目中,如果你是脚手架搭建的,可能需要改一下,CV自己需要的部分)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
<style>
*{
margin-top:20px
}
.demo1{
height: 50px;
background-color: skyblue;
}
.box1{
background-color: orange;
}
.box2{
background-color: red;
}
.list{
width:200px;
height: 200px;
background-color: aqua;
overflow: auto;
}
.list li{
height: 100px;
}
</style>
</head>
<body>
<div id="root">
<!-- prevent 住址默认事件,底层用的是e.preventDefault() -->
<!-- a标签的默认事件是跳转页面,当被prevent修饰后,就不再跳转了,而只是执行showInfo()方法 -->
<!-- 不被prevent修饰时,会先执行showInfo,然后跳转页面 -->
<a href="http:www.atguigu.com" @click.prevent="showInfo">点我提示信息(阻止默认事件)</a>
<!-- 阻止事件冒泡。如果不加,则点击按钮后,button和div都会执行showInfo方法。从里边向外冒 -->
<!-- 底层用的是e.stopPropagation() -->
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息(阻止事件冒泡)</button>
</div>
<!-- 事件只触发一次。即按钮第一次点击才有效,以后点击就无效了 -->
<button @click.once="showInfo">点我提示信息(事件只触发一次)</button>
<!-- 使用事件的捕获模式。捕获是从外到内的,冒泡是从内到外的,先经历捕获再经历冒泡 -->
<!-- 往水里扔石头,从水面到水底是捕获,泡泡从下到上是冒泡 -->
<!-- 点击里面的div2时,会先输出1,然后输出2,因为div1开启了事件的捕获模式,
在事件捕获阶段就执行了showMsg(1) -->
<div class="box1" @click.capture="showMsg(1)" >div1
<div class="box2" @click="showMsg(2)" >div2</div>
</div>
<!-- 只有event.target等于当前元素时才触发事件(即只有自己才能触发)。 -->
<!-- 下面这个例子,使用self,同样阻止了事件冒泡 -->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
<!-- passive: passive被动的
事件的默认行为立即执行,无需等待事件的回调执行完毕
-->
<!-- @scroll是监听滚动条的滚动。@wheel是监听鼠标滚动轮的滚动,鼠标滚轮只要滚动一次,
@wheel就会触发一次,即使滚动条已经到底 .@scoll默认就是异步的,不需要passive修饰,
先将滚动条滚动,再去执行回调函数,当回调函数执行过程中,
用户再次滚动,则还是先去响应滚动条,滚动完毕后,继续执行回调函数。
@wheel="show"默认是先执行完回调函数,滚动条才往下走,显得很卡,可以用passive修饰
@wheel.passive="show"
-->
<ul @scroll="show" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script>
const vm = new Vue({
el: "#root",
methods:{
showInfo(){
alert("同学你好")
},
showMsg(number){alert(number)},
show(){
for (let i = 0; i <100000 ; i++) {
console.log('#')
}
}
}
})
</script>
</body>
</html>
按键修饰符(键盘事件处理)
事件处理 — Vue.js (vuejs.org)https://v2.cn.vuejs.org/v2/guide/events.html
事件处理 — Vue.js (vuejs.org)