事件
Vue 中的 this
实例
在
Vue
中调用document.addEventListener
添加事件回调函数时,在回调函数中调用this
对象时,通过可以调试发现,this
指向的是之前调用document.addEventListener
的Vue
对象或者Vue
组件示例<div id="app"> <div @mousedown="mouseDown($event)"></div> </div> <script> new Vue({ el: '#app', methods: { mouseDown(event) { document.addEventListener('mousemove', this.onmousemove) }, onmousemove(event) { // 定义在Vue组件中 console.log(this) }, }, }) </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17但是如果将
onmousemove
写在全局作用域,发现this
指向变成了doucument
,即调用addEventListener
的对象function onmousemove(event) { // 定义在外部 console.log(this) } new Vue({ el: '#app', methods: { mouseDown(event) { document.addEventListener('mousemove', onmousemove) }, }, })
1
2
3
4
5
6
7
8
9
10
11
12
为什么addEventListener
绑定的回调方法是Vue
对象内部的methods
方法时,this
指向的对象就是当前Vue
对象呢,通过查看源码发现**Vue
在初始化methods
对象时,会将methods
里面的每个函数绑定到当前的Vue
对象**,代码如下:(详细分析见该博客)
键盘事件
常用键盘事件
- keydown
- keyup
响应特定按键
原始:
event.keycode
判断// 绑定的函数 showInfo(e) { if(e.keyCode == 13){ // ... } },
1
2
3
4
5
6Vue 中**:按键别名**
<button @keyup.enter="showInfo">点我</button>
1
常用别名
键盘上的每个按键都有自己的名称和编码,例如:Enter(13)
。Vue 对一些常用按键起了别名,方便使用
- 回车 enter
- 删除 delete 捕获“删除”和“退格”键
- 退出 esc
- 空格 space
- 换行 tab 特殊,必须配合 keydown 去使用(因为 tab 键有一个功能,就是切换焦点,按下去焦点就移动到别的元素上去了,所以必须绑定在 keydown)
- 上 up
- 下 down
- 左 left
- 右 right
通过原始名称绑定
对于 Vue 未提供别名的按键,可以使用按键原始的 key 值去绑定。但注意要转为 kebab-case
(多单词小写短横线写法),例如: CapsLock 要写成 caps-lock
// 获取按键的名称
testKey(e){
console.log(e.key, e.keyCode)
}
/*
1 49
Enter 13
Control 17
Shift 16
CapsLock 20
*/
// 通过原始值绑定
<input @keyup.Control="testKey"></input>
<input @keyup.caps-lock="testKey"></input> // 多单词,转成小写加横杠
2
3
4
5
6
7
8
9
10
11
12
13
14
15
系统修饰键(用法特殊)
ctrl
, alt
, shift
, meta
(meta 就是 win 键)
- 配合 keyup 使用时:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
- 配合 keydown 使用:正常触发事件
补充:指定只有 ctr+y 时才响应:使用 @keyup.ctrl.y
通过 keyCode 绑定事件(不推荐)
也可以使用 keyCode 去指定具体的按键(但是不推荐,因为该特性已经从 Web 标准中被删除)
<button @keyup.13="showInfo">点我</button>
自定义键名(不推荐)
可以去定制按键别名
Vue.config.keyCodes.自定义键名 = 键码
// 例
Vue.config.keyCodes.huiche = 13,
2
3
4
事件处理(@xxx, $event)
- v-on 绑定的函数需要定义在 Vue 选项中
v-on 绑定的事件函数默认的第一个参数是事件对象(常用来 event.target 获取触发元素)
<button v-on:click="showInfo"></button> ... methods: { showInfo(a, b, c, d) { console.log(a, b, c, d) }, }, // 输出: // PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …} // undefined // undefined // undefined
1
2
3
4
5
6
7
8
9
10
11
12
13methods 中正常定义的函数中的 this 对应着 Vue 实例对象;但如果改成箭头函数,则 this 对应着 window 对象。所以 Vue 中的 methods 中的方法尽量不要写成箭头函数
methods: { showInfo() { console.log(this) // Vue实例对象 }, showInfo: () => { console.log(this) // window }, },
1
2
3
4
5
6
7
8简写方法: @
<button @click='showInfo'>点我</button>
1绑定方法时加不加括号都可以,但是想传参数的话:在模板里写一个
**$event
占位符**,在函数的对应位置定义一个形参接收该参数即可<button v-on:click="showInfo($event, 7)"></button> ... methods: { showInfo(event, number) { console.log(event, number) // PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …} 7 }, },
1
2
3
4
5
6
7methods 中的函数没有做数据代理(没有必要);
methods 中的函数也可以写在 data 选项里,但是会造成不必要的资源浪费,因为 function 不会改变,不需要做数据代理
总结:
- 使用
v-on:xxx
或@xxx
绑定事件,其中 xxx 是事件名 - 事件的回调需要配置在methods对象中,最终会在 vm 上
- methods 中配置的函数,不要用箭头函数,否则 this 就不是 vm 了
- methods 中配置的函数,都是被 Vue 所管理的函数,
this
的指向是**vm
或组件实例对象** @click="demo"
和@click="demo($event)"
效果一致,但后者可以传参
事件的默认参数
如果不手动添加参数,$event
对象会被默认当做实参传入到处理函数中。注意:此时绑定的地方不要加括号。
<div id="app">
<button v-on:click="click">click me</button>
</div>
...
<script>
var app = new Vue({
el: '#app',
methods: {
click(event) {
console.log(typeof event) // object
},
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
- 不需要该 event 对象,自己传入参数
- 既需要传递参数,又需要用到 event 对象,可以通过将一个特殊变量
$event
传入到回调中解决这个问题
<input type="text" v-model="item.count" @change="updateNumber($event,index)" />
<script>
// event为原有的$event参数,当input的值改变时触发。 index为传入的下标。
updateNumber(event, index) {
console.log(event, index);
},
</script>
2
3
4
5
6
7
8
9
简单总结来说:
- 使用不带圆括号的形式,event 对象将被自动当做实参传入;
- 使用带圆括号的形式,我们需要使用 $event 变量显式传入 event 对象。
事件修饰符(stop, prevent, once...)
实例 1:阻止 a 标签的跳转行为
旧方法
<a href="www.baidu.com" @click="showInfo"></a>
methods: {
showInfo(e) {
e.preventDefault(); // 阻止默认事件
alert('abab')
},
},
2
3
4
5
6
7
8
Vue
<a href="www.baidu.com" @click.prevent="showInfo"></a>
这里的 .prevent 就是事件修饰符
Vue 中的事件修饰符
prevent
阻止默认事件(常用)stop
阻止事件冒泡(常用)once
事件只触发一次(常用)capture
使用事件的捕获模式self
只有 event.target 是当前操作的元素时才触发事件(某种程度上也能阻止冒泡)passive
事件的默认行为立即执行,无需等待事件回调执行完毕
补充**:修饰符可以连续写**,比如:
@click.prevent.stop="showInfo"
补充:
self
<div @click.self="showInfo"> <!--button冒泡过来的不会触发事件--> <button @click="showInfo">点我</button> </div>
1
2
3
4passive
正常事件的处理流程:触发事件 → 执行回调函数 → 执行默认行为。但是并不是所有的事件都这样,所以 passive 应用并不多。
组件的自定义事件($emit, $on)
- 一种组件间通信的方式,适用于:子组件 ===> 父组件。
- 使用场景:子组件想给父组件传数据,那么就要在父组件中给子组件绑定自定义事件(事件的回调在父组件中)
- 子组件里手动触发该自定义事件,并传入数据,父组件里绑定了这个事件的回调函数的话就可以在回调函数中接收到参数了。
与通过 props 将方法名传给子组件的区别:
- props 的方式,是把方法传给子组件,让子组件自己去调用
- 自定义事件的方式,是把方法作为事件的回调在使用,不需要把方法传给子组件。
绑定自定义事件:
第一种方式,在父组件的模板中直接绑定
<Demo @事件名="方法"/> // 或 <Demo v-on:事件名="方法"/>
1
2
3第二种方式,在父组件中
this.$refs.demo.$on('事件名', 方法)
。可以更加灵活<Demo ref="demo"/> ...... mounted(){ this.$refs.demo.$on('atguigu',this.test) }
1
2
3
4
5若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法<Demo @事件名.once="方法"/> // 或者 mounted(){ this.$refs.demo.$once('atguigu',this.test) }
1
2
3
4
5
6
触发自定义事件
// 子组件中
this.$emit('事件名', 传递的数据)
2
解绑自定义事件
// 解绑单个自定义事件
this.$off('事件名')
// 解绑多个
this.$off(['事件名1', '事件名2'])
this.$off() // 解绑全部
2
3
4
5
6
绑定原生事件(Vue2.x)
组件上也可以绑定原生 DOM 事件,需要使用 native 修饰符 @click.native="show"
上面绑定自定义事件,即使绑定的是原生事件也会被认为是自定义的,需要加 native,加了后就将此事件给组件的根元素。(Vue3 中不需要了)
注意
- 通过
this.$refs.xxx.$on('事件名',回调函数)
绑定自定义事件时,回调函数要么配置在methods
中,要么用箭头函数
,否则 this 指向会出问题(指向子组件实例对象)。 - 组件销毁后自定义事件也销毁了(原生事件不受影响)