问题起因
在项目开发中偶然碰到如下场景
// 某个vue组件
{
create: () => {
// Bus是数据总线
Bus.$on("load")
},
beforeDestroy: () => {
Bus.$off("load")
}
}
当这个组件卸载,并且重新渲染后,就接收不到load事件了。
输出日志点后发现:竟然是先触发off方法。也就是先触发create再触发beforeDestroy的
测试案例
创建一个简单的vue程序进行测试
<html>
<head></head>
<body>
<div id="app">
<component :is="curComp"></component>
<button @click="changeComp">切换</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component("compA", {
template: "<li>compA</li>",
created: () => {
console.log("compA create");
},
mounted: () => {
console.log("compA mounted");
},
beforeDestroy: () => {
console.log("compA beforeDestroy");
},
});
Vue.component("compB", {
template: "<li>compB</li>",
created: () => {
console.log("compB create");
},
mounted: () => {
console.log("compB mounted");
},
beforeDestroy: () => {
console.log("compB beforeDestroy");
},
});
var app = new Vue({
el: "#app",
data: {
curComp: "compB"
},
methods: {
changeComp: function () {
this.curComp = this.curComp === "compA" ? "compB" : "compA";
}
},
});
</script>
</body>
</html>
切换时的情况确认了上述的想法:create在beforeDestroy之前调用
原理分析
要分析原理就不得不提diff算法了(为了研究这个问题又复习了一下相关原理(可以参考juejin.cn/post/736197…
- 当component变化时,因为是替换node,首尾匹配肯定是匹配不上了。这时候进入查找逻辑。
- 查找逻辑中,如果找不到就直接走
createElm创建新的节点了。这时候就会触发create周期 - 在最后,vue才会将oldVNode中剩余的节点通过
removeVnodes去掉,触发beforeDestroy周期
分析结束,确实与上述事实对应。最终在总线事件名后拼接了ip进行处理