生命周期
每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁
组件从创建到销毁的一系列过程叫做组件的声明周期。
vue在整个生命周期里面提供了一些函数,可以在内部实现一些业务逻辑,
并且这些函数会在一些特定的场合下去执行。(在生命周期的某一个时刻进行触发)
组件的生命周期钩子函数大致可以分为三个阶段:初始化、运行中、销毁
初始化阶段: beforeCreate created beforeMount mounted
运行中阶段: beforeUpdate updated
销毁阶段: beforeDestroy destroyed
-
实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载到,只是一个空壳,无法访问到数据和真实的dom,一般不做操作
-
挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里同步更改数据不会触发updated函数,一般可以在这里做初始数据的获取。 做异步ajax,绑定初始化事件
-
接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,这是在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始化数据的获取
-
接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情…
-
当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿
-
当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的dom
-
当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等
-
组件的数据绑定、监听…去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以
实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created 钩子可以用来在一个实例被创建之后执行代码:
new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。
不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch(‘a’, newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
来一波代码带你领略其钩子函数的风采:
HTML代码:
<div id="app">
<my-component></my-component>
</div>
<!-- 定義組件的模板結構 -->
<template id="my-component">
<div>
<h1 id="title">hello{{msg}}</h1>
<p>
<input type="text" v-model='msg'>
</p>
</div>
<!-- 定義組件的結構模板 -->
<template id="my-component">
<div>
<h1 id="title">hello {{msg}}</h1>
<p>
<input type="text" v-model="msg">
</p>
<button @click='destroy'>銷毀組件</button>
</div>
</template>
</template>
JS代码:
//初始化阶段
//1.一个组件或者实例的生命周期都是通过new开始的
//2.实例化之后,内部会做一些初始化事件与生命周期相关的配置
Vue.component('my-component', {
template: '#my-component',
data() {
return {
msg: 1
}
}, methods: {
destroy() {
this.$destroy()
}
},
//3.这个钩子函数初始化的时候立马执行,此钩子函数里面是获取不到数据的
//同时页面中的真实dom节点也没有挂载出来,null
beforeCreate() {
console.log('beforeCreate')
console.log(this.msg, document.getElementById('title'))
},
//4.created钩子函数内部的数据已经被挂载了,但是真实dom节点还是没有渲染出来
//在这个钩子函数里面,如果同步的去更改数据的话,运行中钩子函数是不会执行的。
//通常会在此钩子函数里面进入ajax的异步操作,另外还可以做一些初始化事件的绑定
created() {
console.log('created')
console.log(this.msg, document.getElementById('title'))
this.timer = setInterval(() =>{
this.msg++
},3000)
},
//5.接下来的过程,就是组件或者实例去查找各自的模板,让后将其编译成虚拟dom,即将放入render函数中做初始化渲染的操作。
//6.beforeMount代表dom马上就要被渲染出来了,但是还没有真正的在页面中渲染出来
//此钩子函数与created钩子函数基本一致,可以做ajax与初始化事件的绑定操作
beforeMount() {
console.log('beforeMount')
console.log(this.msg, document.getElementById('title'))
},
//生成好了虚拟dom,然后在render函数里面替换对应的el,渲染成真实dom节点
//相当于在render函数里面做了一个初始化渲染的操作
// render(){ //相当于把组件内部的render函数覆盖了。自己的render是将虚拟dom渲染成真实dom的操作
// console.log("render.....")
// }
//7.mounted钩子函数是初始化阶段的最后一个钩子函数
//数据已经挂载完毕了,真实的dom也已经渲染出来了
//这个钩子函数可以用来做一些实例化的相关操作 ===> 拖拽
mounted() {
console.log('mounted')
console.log(this.msg, document.getElementById('title'))
},
//8.运行时钩子函数初始化阶段是不会主动执行的
//只有dom挂载完毕了,
//然后再去当数据发生变化的时候,beforeUpdate这个钩子函数才会执行
beforeUpdate() {
console.log('beforeUpdate')
console.log(this.msg, document.getElementById('title'))
},
//9.這個鉤子函數裡面dom獲取的數據內容是更新後的內容
//生成新的虛擬dom,與上一次的虛擬dom結構進行對比,比較出來差異(diff算法)再去進行真是dom的重新渲染操作
//这里的updated中的真实dom里面显示的数据就是跟你在内存里面的data里的数据趋于一致
updated() {
console.log('updated')
console.log(this.msg, document.getElementById('title').innerHTML)
},
//10.当组件销毁的时候,就会触发执行 vm.$destroy()的时候,组件就会被销毁
//钩子函数销毁之前可以做一些清楚事件绑定,定时器操作
beforeDestroy(){
//清除定时器
clearInterval(this.timer)
console.log('beforeDestroy')
},
//11.组件一旦被销毁了,组件的dom结构还是存在的
//只是组件的双向数据绑定、事件监听、watch相关的已经被移除
destroyed(){
console.log('destroyed')
}
})
new Vue({}).$mount('#app')