生命周期
- 每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。
钩子函数
- vue在整个生命周期里面提供了一些函数,可以在内部实现一些业务逻辑,并且这些函数会在一些特定的场合下去执行。(在生命周期的某一个时刻进行触发)
- 组件的生命周期中钩子函数在三个阶段中的分布大概如下:
初始化阶段: beforeCreate created beforeMount mounted
运行中阶段: beforeUpdate updated
销毁阶段: beforeDestroy destroyed
我们接下来从初始化开始慢慢了解。
一. 初始化阶段
1. beforeCreate
这个钩子函数初始化的时候立马执行,此钩子函数里面是获取不到数据的,同时页面中的真实dom节点也没有挂载出来
<body>
<div id="app">
<my-component></my-component>
</div>
<!--定义组件的模板结构-->
<template id="my-component">
<div>
<h1 id="title">{{msg}}</h1>
<p><input type="text" v-model="msg"></p>
</div>
</template>
<script>
Vue.component("my-component",{
template:"#my-component",
data(){
return {
msg:1
}
},
//1.这个钩子函数初始化的时候立马执行,此钩子函数里面是获取不到数据的
//同时页面中的真实dom节点也没有挂载出来,null
beforeCreate(){
console.log("beforeCreate....")
console.log(this.msg,document.getElementById("title"))
}
})
new Vue({}).$mount("#app");
</script>
</body>
结果如下:拿不到数据,也拿不到dom节点
2. created
created钩子函数内部的数据已经被挂载了,但是真实dom节点还是没有渲染出来,在这个钩子函数里面,如果同步的去更改数据的话,运行中钩子函数是不会执行的。通常会在此钩子函数里面进入ajax的异步操作,另外还可以做一些初始化事件的绑定
created(){
console.log("created...")
console.log(this.msg,document.getElementById("title"))
},
结果如下:能拿到数据,但是拿不实dom节点
3. beforeMount
接下来的过程,就是组件或者实例去查找各自的模板,让后将其编译成虚拟dom,即将放入render函数中做初始化渲染的操作。beforeMount代表dom马上就要被渲染出来了,但是还没有真正的在页面中渲染出来,此钩子函数与created钩子函数基本一致,可以做ajax与初始化事件的绑定操作
beforeMount(){
console.log("beforeMount....")
console.log(this.msg,document.getElementById("title"))
},
结果如下:拿得到数据,却拿不到dom节点
4. mounted
生成好了虚拟dom,然后在render函数里面替换对应的el,渲染成真实dom节点,相当于在render函数里面做了一个初始化渲染的操作,但是这个render函数不会显示出来,Vue会自动在这里面初始化渲染
mounted钩子函数是初始化阶段的最后一个钩子函数,数据已经挂载完毕了,真实的dom也已经渲染出来了,这个钩子函数可以用来做一些实例化的相关操作 ——> 拖拽等
mounted(){
console.log("mounted.....")
console.log(this.msg,document.getElementById("title"))
}
结果如下:数据和dom节点在此时都可以拿得到了
二. 运行阶段
1. beforeUpdate
运行时钩子函数初始化阶段是不会主动执行的,只有dom挂载完毕了,然后再去当数据发生变化的时候,beforeUpdate这个钩子函数才会执行,beforeUpdate钩子函数里面,这在里获取dom里面的数据内容是更新之前的内容.
beforeUpdate(){
console.log("beforeUpdate",this.msg)
console.log("beforeUpdate....",document.getElementById("title").innerHTML)
}
- 当数据没有被改变时,控制台不会打印出来(数据默认是 1)
- 当数据被改变时,就会打印出数据,也就是 1 。此时的数据已经被修改成了12.
注意:此时打印出来的数据是修改之前的数据
因为 this.msg是通过v-model双向数据绑定的,所以会实时拿到数据,此处要注意,这里是为了对比,所以将它打印出来。
2. updated
updated钩子函数里面,这在里获取dom里面的数据内容是更新之后的内容,生成新的虚拟dom,与上一次的虚拟dom结构进行对比,比较出来差异(diff算法),再去进行真实dom的重新渲染操作。
updated(){
console.log("updated",this.msg)
console.log("updated",document.getElementById("title").innerHTML)
}
- 数据没有被改变之前,控制台一样不会打印出来
- 当你修改数据时,控制台就会打印出数据,此时数据被修改成12
注意:此时拿到的数据却不是修改前的数据了,而是修改后的数据,这也就是beforeUpdate钩子函数与updated钩子函数的区别,一个是拿到以前的数据,而另一个却是拿到修改后的数据
三. 销毁阶段
1. beforeDestroy
当我们点击销毁组件按钮时,就会触发执行 vm.$destroy()的时候,组件就会被销毁了,这个钩子函数代表销毁之前,可以做一些清除事件绑定,清除定时器操作。
<template id="aaa">
<div>
<h1 id="title">{{msg}}</h1>
<p><input type="text" v-model="msg"></p>
<button @click="destroy">销毁组件</button>
</div>
</template>
methods:{
destroy(){
// console.log(122)
this.$destroy()
}
}
- 比如我们在create钩子函数中绑定一个计时器
created(){
//定时器
this.timer= setInterval(() => {
this.msg++
console.log(1111);
}, 1000);
},
- 当我们销毁组件的时候,计时器却不会一起销毁,还会一直运行,这样会占据内存,所以我们需要把计时器销毁
- 所以这时候就需要我们在beforeDestroy中关闭计时器
beforeDestroy(){
console.log("beforeDestroy");
//清除初始化时绑定的计时器
clearInterval(this.timer)
}
2. destroyed
组件一但被销毁了,组件的dom结构还是存在的,只是组件的双向数据绑定,时间监听,watch相关已经被移出了。
destroyed(){
console.log("destroyed");
}
- 此时组件已经没有用了,数据也不会双向绑定了