我们上一个文章写的是给自定义事件绑定,现在我们写的是给绑定的自定义事件解绑,一般来说如果我们绑定了事件,如果不解绑,它就会一直存在,就算不使用也存在,所以我们要如何解绑自定义事件呢?
解绑自定义事件
一般来说,你给谁绑定的事件,你就给谁解绑,我们在MyStudent绑定的事件,就在MyStudent解绑事件,我们先在MyStudent加一个按钮,给按钮绑定一个点击事件,写一个unbind方法
解绑一个自定义事件
然后在unbind方法里,我们要在实例对象一个$off的api来解绑事件
网页上如果你不点击解绑按钮,一直点击上传学生名按钮,App会一直收到学生名
一旦你点击了解绑按钮
你后面再怎么点击上传学生名按钮,App都不会再收到学生名
解绑多个自定义事件
但是这样只适用解绑一个自定义事件,如果我们要解绑多个自定义事件呢?在App.vue上我们再给student组件加上一个自定义事件demo
在MyStudent触发一下demo,我们不再另写按钮,直接在上传学生名按钮下,触发xuesheng的同时触发demo,记得不要写mi,mi只是demo的回调名,要写demo
网页上点击上传按钮后,两个事件就同时被触发了
如果要同时要解绑两个事件,就要把两个事件放在一个数组了,再用$off来解绑
网页上没有点击解绑按钮前,一直点击上传学生名按钮,两个事件都会被触发
一旦你点击了解绑按钮
你后面再怎么点击上传学生名按钮,App都不会再收到学生名和demo
解绑所有自定义事件
$off后面不加任何参数,这样就直接解绑所有的自定义事件
网页上没有点击解绑按钮前,一直点击上传学生名按钮,所有事件都会被触发
一旦你点击了解绑按钮
你后面再怎么点击上传学生名按钮,App都不会再收到任何自定义事件的回调
生命周期的beforeDestroy和Destroyed
接下来我们来讲一下我们之前写到过的生命周期(《17.生命周期》),vm被销毁后就拆除掉了监视属性、子组件和事件监听器(指的是自定义事件不包括DOM的原生事件);除了vue的实例对象vm可以用生命周期的钩子,组件的实例对象vc也可以使用生命周期的钩子,接下来我们来实验一下:
销毁MyStudent的vc
添加一个销毁按钮
组件实例对象vc可以使用生命周期的钩子
为了展示得更明白些,我添加了一些代码
网页上,点击number++按钮,add会被调用,页面上的“当前求和为:”也在++,就是说响应式在的
但当我点击销毁按钮后
再去点击number++按钮,add(DOM的原生事件)依旧被调用,但是响应式丢了,页面上的“当前求和为:”不再变化依旧是0
由于 vue.js 版本的问题,即2.7.0 及以上版本执行完 this.$destory() 指令后,原生DOM的响应事件不会被触发,原生 DOM 事件无法被调用了。执行完npm list vue,我发现我的版本是2.7.0 及以上版本,
所以执行完 this.$destory() 指令后,我的原生DOM事件无法被调用
而且在我点销毁按钮前,我是可以上传学生名的
但当我点击销毁按钮后,
再点击上传按钮后,我无法上传学生名了,这更加印证了vc销毁后,它身上的自定义事件也就不奏效了
销毁root的vm
在main.js的vm上,加一个mounted钩子,里面添加一个计时器,3秒后销毁vm
网页上前3秒,我点上传学生名按钮,组件的自定义事件可以被调用,但当3秒后,再怎么点击该按钮,组件的自定义事件不能被调用了
这样我们就验证了下面这两个了
这结主要的代码如下:
MyStudent.vue
<template>
<div class="student">
<h1>学校姓名:{{ name }}</h1>
<h1>学生年龄:{{ age }}</h1>
<h1>当前求和为:{{ number }}</h1>
<button @click="add">number++</button>
<button @click="sendStudentname">上传学生名给App</button>
<button @click="unbind">解绑xuesheng事件</button>
<button @click="death">销毁当前Student组件的实例对象(vc)</button>
</div>
</template>
<script>
// 组件交互相关的代码(数据、方法等等)
export default {
name: "MyStudent",
data() {
return {
name: "小蒲",
age: 18,
number: 0,
};
},
methods: {
add() {
console.log('Dom原生事件add被调用')
this.number++;
},
sendStudentname() {
// 触发Student组件实例对象上的xuesheng事件
this.$emit("xuesheng", this.name, 111, 222, 333);
this.$emit("demo");
},
unbind() {
this.$off("xuesheng"); //只适用解绑一个自定义事件
this.$off(["xuesheng", "demo"]); //只适用解绑多个自定义事件
this.$off(); //解绑所有自定义事件
},
death() {
this.$destroy();//销毁了当前Student组件的实例,销毁后所以Student实例的自定义事件全都不奏效了
},
},
};
</script>
<style lang="less">
.student {
background-color: pink;
padding: 5px;
margin-top: 30px;
}
</style>
App.vue
<template>
<div class="App">
<h1>{{ msg }}</h1>
<!-- <h2>{{ Schoolname }}</h2> -->
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
<School :getSchoolname="getSchoolname" />
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)-->
<!-- <Student v-on:xuesheng="getStudentname" /> -->
<Student @xuesheng="getStudentname" @demo="m1" />
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref)-->
<!-- <Student ref="student" /> -->
</div>
</template>
<script>
// 引入组件
import School from "./components/MySchool.vue";
import Student from "./components/MyStudent.vue";
export default {
name: "App",
components: { School, Student },
data() {
return {
msg: "你好啊",
Schoolname: "",
};
},
methods: {
getSchoolname(name) {
console.log("App收到了学校名", name);
// this.Schoolname = name;
},
getStudentname(name, ...params) {
console.log("App收到了学生名", name, params);
},
m1(){
console.log('demo事件被触发了!')
}
},
// mounted() {
// setTimeout(() => {
// // this.$refs.student.$on("xuesheng", this.getStudentname);
// this.$refs.student.$once("xuesheng", this.getStudentname)(一次性);
// }, 3000);
// },
};
</script>
<style>
.App {
background-color: gray;
padding: 5px;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
mounted(){
setTimeout(()=>{
this.$destroy()
},(3000))
}
}).$mount('#app')