首先声明事件的解绑他不是必须的,但他一定是推荐的。这就跟定时器的关闭一样,我们只要开启就应该选择一个合适的时机关掉,但是你不关,就等着用户关网页,也是可以的。
我们在上一篇的基础上对事件进行解绑。
解绑使用的语法:$off(事件名)
注意:在哪了绑定的,就在哪里解绑
代码实现如下:
<template>
<div class="demo">
<h2 class="stu" >学生名称:{{name}}</h2>
<h2 >学生年纪:{{age}}</h2>
<button @click="studentNameGetter(name)">点击将学生名称交给父组件App</button>
<button @click="unbind">点击解绑事件</button>
</div>
</template>
<script>
export default {
name:'MyStudent',
data(){
return {
name:'张三',
age:18
}
},
methods:{
studentNameGetter(name){
// 触发Student组件实例身上的stuName事件
this.$emit('stuName',name)
},
unbind(){
this.$off('stuName')
}
}
}
</script>
但是如上的方法只能解绑一个自定义事件,如果我们有多个自定义事件需要解绑,则在上面的方法中传入一个数组即可:
$off(['事件1',‘事件2’,......])
Tips:
$off()
如果什么都不传,则会把这个组件实例身上所有的自定义事件全部解绑
要点回顾:
在销毁vm执行了$destroy()之后,会关闭所有的监听器,子组件,以及事件监听器。这时原生的DOM事件可以使用,因为他拆掉的是自定义事件的事件监听器。
App组件
<template>
<div>
<h2 ref="title" >欢迎来到{{n}}</h2>
<hr>
<SchoolName :getSchoolName="getSchoolName"></SchoolName>
<StudentName ref="Student"></StudentName>
<!-- <StudentName v-on:stuName="getStudentName"></StudentName>-->
<!-- <StudentName @stuName ="getStudentName"></StudentName>-->
</div>
</template>
<script>
import SchoolName from "@/components/School";
import StudentName from "@/components/Student";
export default {
components:{
SchoolName,
StudentName
},
data(){
return {
n:'CSDN'
}
},
methods:{
getSchoolName(name){
console.log('App组件已经收到了学校的名字:',name)
},
getStudentName(name){
console.log('App组件已经收到了学生的名字:',name)
}
},
mounted() {
this.$refs.Student.$on('stuName',this.getStudentName)
}
}
</script>
在$on()方法中第二个参数我们既然传入的是一个函数,那么我们能不能直接将函数定义在on方法中,而不是在methods中定义呢?
App组件:
<script>
import SchoolName from "@/components/School";
import StudentName from "@/components/Student";
export default {
components:{
SchoolName,
StudentName
},
data(){
return {
n:'CSDN'
}
},
methods:{
getSchoolName(name){
console.log('App组件已经收到了学校的名字:',name)
},
// getStudentName(name){
// console.log('App组件已经收到了学生的名字:',name)
// }
},
mounted() {
this.$refs.Student.$on('stuName',function (name) {
console.log(this)
console.log('App组件已经收到了学生的名字:',name)
})
}
}
</script>


我们发现this的指向并不是App
注意:谁触发了这个事件,此时$on()方法中this指向就是谁
这种情况造成的影响就是如果我们想要把从子组件传递过来的数据挂载到当前父组件的身上的时候,会发现挂载不上,因为此时this的指向已经不是这个父组件了
那么我们怎么解决这个问题呢?两种方法:
代码如下:
<script>
import SchoolName from "@/components/School";
import StudentName from "@/components/Student";
export default {
components:{
SchoolName,
StudentName
},
data(){
return {
n:'CSDN'
}
},
methods:{
getSchoolName(name){
console.log('App组件已经收到了学校的名字:',name)
},
// getStudentName(name){
// console.log('App组件已经收到了学生的名字:',name)
// }
},
mounted() {
this.$refs.Student.$on('stuName',(name) => {
console.log(this)
console.log('App组件已经收到了学生的名字:',name)
})
}
}
</script>
此时的this就是App组件了:

我们在给组件绑定一些原生的DOM事件的时候,会发现不能被触发,这是因为Vue会把一切在组件上绑定的事件当作自定义事件。

那么我们怎么解决这个问题呢?使用.native事件修饰符即可:

如此这个事件才会被当作原生的DOM事件去解析。
他的底层是把click事件交给了Student组件的最外层元素。
Student组件:

也就是这个大的div。
此处也从侧面印证了一个事实:组件的template里面只能有一个根元素!
如果有多个的话,此时你的click事件应该给谁呢?(当然这只是其中一个印证方向)
组件的自定义事件
一种组件间通信的方式,适用于:子组件 ===> 父组件
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
绑定自定义事件:
第一种方式,在父组件中:<Demo @eventName="test"/>或 <Demo v-on:eventName="test"/>
第二种方式,在父组件中:
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('eventName',this.test)
}
若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
触发自定义事件:this.$emit('eventName',数据)
解绑自定义事件this.$off('eventName')
组件上也可以绑定原生DOM事件,需要使用native修饰符。
注意:通过this.$refs.xxx.$on('eventName',回调)绑定自定义事件时,回调要么配置在methods中要么用箭头函数,否则this指向会出问题!