先上个codesandbox地址
代码不多,也直接贴上来了
// 父组件
<template>
<div id="app">
<div v-if="a">header</div>
<div>
<Child1/>
</div>
<div v-if="!a">footer</div>
</div>
</template>
<script>
import Child1 from "./components/Child1.vue";
export default {
components: {
Child1
},
data() {
return {
a: false
};
},
mounted() {
console.log("parent mounted");
this.a = !this.a;
}
};
</script>
// 子组件
<template>
<div>
123
</div>
</template>
<script>
export default {
name: "Child1",
mounted() {
console.log("child mounted");
}
};
</script>
父组件结构很简单,从上到下一共有三个div
,其中第一个和第三个都有个v-if
,并且对应的值相反,也就是说这两个div
永远只会显示一个。而中间的div
里面包裹着一个子组件。然后在父组件的mounted
钩子上变换了a
的值,使得两个div
的v-if
状态变化。这时我发现子组件的mounted
方法又执行了一遍,或者说,子组件被重新创建了。控制台打印的结果是
child mounted
parent mounted
child mounted
接着,我把包裹着子组件的那个div
去掉了,让子组件和其余两个div
处于同一级,这时我发现,子组件的mounted
方法只执行了一次。控制台的打印结果是
child mounted
parent mounted
就算在子组件里面再加上一个孙组件,他也只mounted
了一次。
我了解了一下vue的diff算法,想试着去解释这个现象,但是还是解释不通,这种情况下,中间的这个节点不应该是作为相同的节点被保留下来的吗?
希望有大神老师可以解答一下我的疑问:
1.我知道v-if
和v-show
的区别,也知道mounted
和beforeMount
的区别,我就是不知道在现在的情况下为什么会有这种mounted
两次的现象。
2.我不太明白子组件是否被div
包裹有什么区别。
3.又试验了一下,如果这里的a
的初始值是false
,会打印出两次mounted
,而初始值是true
,子组件就只创建一次。但当这时我给第一个这跟节点的先后顺序还有关系?div
加上一个随意的内联style,比如style="color:white;"
,两次mounted
就又出现了,(这个原因是diff算法有关,算法判断是否是相同的节点,会看attribute是否一样)
4.把子组件的mounted
换成created
效果一样。
5.把父组件的结构改成
<div v-if="a">header</div>
<div>
<Child1/>
</div>
<div v-if="a">footer</div>
这时无论a的初始值是什么,都会打印两次mounted。
mounted钩子函数中修改a的值,渲染header
<div v-if="a">header</div>
时,复用了原来的子组件的外层div。所有子组件要重新渲染一次。如果a初始是true,此时mounted钩子函数中修改a的值,会先销毁header
<div v-if="a">header</div>
,不会影响子组件,也不会再次渲染。