Vue 生命周期 详细介绍(面试必考,内附实例截图)
Vue的生命周期是不仅是面试必考点,理解它更能为我们在Vue项目开发带来促进作用。什么是Vue的生命周期?每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。简单理解就是Vue实例从创建到销毁的这么一个过程。如图
Vue的生命周期是不仅是面试必考点,理解它更能为我们在Vue项目开发带来促进作用。
什么是Vue的生命周期?
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。简单理解就是Vue实例从创建到销毁的这么一个过程。如图(官网)所示:
Vue生命周期函数(钩子)执行顺序
从上图可知主要为八大生命周期钩子:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。执行顺序为上图所示顺序。
验证生命周期钩子执行顺序:
new Vue({
el: '#app',
router,
store,
data: {
greet: 'hello world'
},
template: '<div>我是模板内的{{greet}}</div>',
beforeCreate() {
console.log('------beforeCreate------')
},
created () {
console.log('------created------')
},
beforeMount () {
console.log('------beforeMount------')
},
mounted () {
console.log('------mounted------')
},
beforeUpdate () {
console.log('------beforeUpdate------')
},
updated() {
console.log('------updated------')
},
beforeDestroy() {
console.log('------beforeDestroy------')
},
destroyed() {
console.log('------destroyed------')
}
})
打印结果如下:
我们发现只打印出了四个钩子中的信息,即首次创建实例过程中,只执行四个生命周期钩子,beforeCreate、created、beforeMount、mounted,执行顺序与生命周期图一致,beforeUpdate与updated是在数据更新时候执行,而beforeDestroy与destroyed是在实例销毁的时候执行。在每个生命周期钩子执行期间或者之后都会进行一些相关的操作,以下分析这期间都做了什么工作。
生命周期函数(钩子)详解
结合生命周期图,进一步分析。
new Vue()
创建一个vue实例,然后init初始化event 和 lifecycle,期间分别调用了3个初始化函数(initLifecycle(), initEvents(), initRender()),初始化了生命周期,事件以及定义createElement函数。在初始化生命周期时,定义了一些属性,比如生命周期状态_isMounted ,_isDestroyed ,_isBeingDestroyed,表示keep-alive中组件状态的_inactive。初始化event,定义了$once、$off、$emit、$on几个函数。createElement函数是在初始化render时定义的(调用了initRender函数)。
beforeCreate
beforeCreate执行结束后,数据初始化,定义data数据、方法及事件,并且通过Object.defineProperty()来实现数据劫持以及给组件实例配置watcher观察者实例(发布-订阅者模式),即实现数据双向绑定,后续当数据发生变化时,感知数据变化并完成页面渲染。
示例:
beforeCreate() {
console.log('------beforeCreate------')
console.log(this.greet)
console.log(this.$el)
}
created
该钩子中我们可以拿到data下的数据以及methods下的方法了。在这个钩子中,我们可以开始调用方法进行数据请求了。
created执行结束后,判断当前是否有el参数,如果有,继续判断是否有template参数。如果没有el,那么我们会等待调用$mount(el)方法(即手动挂载)。
确保有了el后,往下判断当有template参数时,将template模板转换成render函数(在此之前判断当前是否有render函数,如果有,则会直接去渲染当前的render函数,如果没有则查找是否有template模板),如果没有template,将直接获取到的el(也就是我们常见的#app)编译成template,然后在将这个template转换成render函数。
示例:
created () {
console.log('------created------')
console.log(this.greet)
console.log(this.$el)
}
beforeMount
在creted到beforeMount之间,最主要的工作就是将模板或者el转换为render函数。这里需要注意,不管是用el,还是用template,或者是.vue文件(如果是.vue文件,会先编译成template),最终都会被转换为render函数。
beforeMount执行后,开始渲染render函数了,此时先产生一个虚拟dom(用于后续数据发生变化时,新老虚拟dom对比diff算法),进行保存,然后再开始将render渲染成为真实的dom,替换掉原来的vm.$el,再将替换后的$el append到我们的页面内。基本流程走完。
示例:
beforeMount () {
console.log('------beforeMount------')
console.log(this.greet)
console.log(this.$el)
}
此时$el为“#app”中对应的元素:
之后向下检查到template,用其将#app替换,转换成render函数,渲染成真实dom后,替换了原来的$el。往下观察mounted打印信息。
mounted
执行mounted,将标识生命周期的一个属性_isMounted 置为true。在mounted钩子内,我们可以操作dom,因为这个时候dom已经渲染完成了。
示例:
mounted () {
console.log('------mounted------')
console.log(this.greet)
console.log(this.$el)
}
上面说到检查到template,转换成render函数,渲染成真实dom后,替换了原来的$el(#app)。
beforeUpdate、updated
当数据变化时,触发beforeUpdate,将我们变化后的数据渲染到页面上了(此时判断当前的_isMounted是不是为ture且_isDestroyed是不是为false,保证dom已经被挂载的情况,且当前组件并未被销毁,才会执行update)
beforeUpdate执行结束之后,重新生成一个新的虚拟dom(Vnode),用它和原来的Vnode做比较(diff算法),更新render函数中的数据,之后将render函数渲染成真实dom,完成页面更新。
继续执行updated,此时updated里面可以获取到更新之后的dom且可以对其进行操作。
示例:
添加一个改变数据的方法
未点击按钮
更新钩子函数打印信息
beforeUpdate () {
console.log('------beforeUpdate------')
console.log(this.greet)
console.log(this.$el)
},
updated() {
console.log('------updated------')
console.log(this.greet)
console.log(this.$el)
}
点击按钮后
beforeDestroy、destroyed
beforeDestroy钩子内仍可以该实例仍可用,之后会执行一系列的销毁动作,解除各种数据引用,移除事件监听,删除组件_watcher,删除子实例等。同时将实例属性_isDestroyed置为true。销毁完成后,执行destroyed。生命周期阐述完毕。
tips:实例挂载方式
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app') //不存在el,手动调用$mount进行挂载
以上生命周期为Vue2.x版本,Vue3.x版本生命周期有所改变,在此不展开,有兴趣的可以自行了解,附上两个版本生命周期对比图:
更多推荐
所有评论(0)