我们都知道,v-if
指令是删除和新建dom
(组件对应的本质上也就是一堆DOM+js+css).
对于一般的HTML元素来说,是如此.
<div id='app'>
<h1 v-if="showHTML">v-if 删除和修改普通的dom元素</h1>
<button @click="showHTML=!showHTML">普通的HTML元素使用v-if</button>
</div>
var app = new Vue({
el: '#app',
data: {
showHTML: true
}
}
结果:
这没什么毛病,一般讲这些例子,都会这么写的.
虽然,我们拿到不到普通的 HTML
元素的声明周期钩子,但从 Elements 开发工具选项卡可以看到的结果.
但实际上,这有一个巨大的坑!!!
2.v-if 用于组件
由于,我们拿不到普通DOM的声明周期钩子(上述的h1
标签.)
仅从浏览器开发工具里查看到DOM元素确实是没有了.
所以,就认定了:
只要使用的
v-if
指令.那么就是对DOM元素的删除或者新建.
2.1 v-if 使用在组件的标签上.
组件,我们拿得到它们的生命周期钩子函数.
我们定义一个HelloWorld
的组件.
并在组件标签上使用v-if来决定组件的新建或者删除.
<div id='app'>
// v-if 在 组件的标签上
<hello-world v-if="showHelloWorld"></hello-world>
<button @click="showHelloWorld=!showHelloWorld">v-if在组件的标签上</button>
</div>
<template id="helloworld">
<div top>
<h1>hello world</h1>
</div>
</template>
Vue.component('HelloWorld', {
template: '#helloworld',
created() {
console.log('helloworld created!')
},
destroyed() {
console.log('helloworld destroyed!')
},
})
var app = new Vue({
el: '#app',
data: {
showHelloWorld: true
}
})
结果:
好像没什么问题诶.v-if就是能正确的触发dom的新建和删除.所以,对应的就触发了组件的 created 和 destroyed 钩子函数!!
2.2 v-if 作用在组件内部的顶级HTML元素上.
定义第一个HelloVue
组件.
<div id='app'>
<hello-vue ref="child"></hello-vue>
<button @click="toggle">v-if在组件内部的顶级HTML元素上</button>
</div>
<template id='hellovue'>
<div top v-if='showSelf'>
<h1>hello vue</h1>
</div>
</template>
Vue.component('HelloVue', {
template: '#hellovue',
data() {
return {
showSelf: true
}
},
methods: {
toggle() {
this.showSelf = !this.showSelf
}
},
created() {
console.log('hello vue created!')
},
destroyed() {
console.log('hello vue destroyed!')
},
})
var app = new Vue({
el: '#app',
methods: {
toggle() {
// console.log(this.$refs.child)
this.$refs.child.toggle()
}
}
})
先看控制台输出:
发现在组件内部即使在顶级HTML使用v-if
,当组件消失时
,并没有按照我们预期的执行组件的 destroyed
函数.
难道是组件的HTML结构没有被删除吗?
看看组件的的HTML结果:
结果表明,组件的HTML结构确实被删除了!!
但是并没有触发组件的 destroyed
声明周期钩子函数!!!
结论
v-if
使用在组件上,表示清除或者新建这个组件.
v-if
作用在普通的HTML
元素上,仅仅表示清除这段DOM
结构.想通过
v-if
依赖生命周期钩子函数,必须把v-if
修饰在组件上或者手动的调用组件的vm.$destroy()
方法。