下面先附上官网的一张图示,附有注释讲解。随着你的不断学习和使用,它的参考价值会越来越高。
所有的生命周期钩子自动绑定this
上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法(例如created: () => this.fetchTodos()
)。这是因为箭头函数绑定了父上下文,因此this
与你期待的 Vue 实例不同。
beforeCreate
在实例创建之前,data中的数据,methods、watch、computed里的方法都还不能访问 打印出来全都是undefined。那么问题来了:如何在这个生命周期获取data中的数据呢?
异步方式获取data:this.$nextTick或者setTimeout都行。相当于在初始化前告诉容器,等整个视图都渲染完毕再跑里面的代码。这种方式别说拿data了,拿渲染完DOM都OK~
同步方式获取data: 在beforeCreate前,所有的options都会先存到vm.$options
中, 就是直接从this.$options.data
里去拿。比如this.$options.data()[key]
就好。如下:
export default {name: 'App',data () {return {b: {name: 'clearlove'}}},beforeCreate () {console.log(this.$options.data()['b'], '实例创建之前') //{ name: 'clearlove'} '实例创建之前'}} // this.$options.data就是上方的data函数复制代码
但是实际情况中,从来没遇到过需要在组件还没初始化就去拿data的……
created
实例已经创建,可以直接使用实例中的数据和方法,但是还不能对DOM节点进行访问。即$el属性不可见。该阶段允许进行异步请求
<template><div id="app"><div id="nav" ref="myDiv"></div></div></template><script>export default {created () {console.log(this.$refs.myDiv, '实例创建完成') // undefined '实例创建完成'}}复制代码
beforeMount
相关的render
函数首次被调用。
mounted
相关的render
函数首次被调用。DOM节点已经渲染,可以进行DOM操作,比如事件监听。该阶段允许进行异步请求,但是如果是父组件异步获取数据要使用props传递给子组件的话,则要在created里去发异步请求。具体原因看下方父子组件的生命周期
beforeUpdate
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。可以修改data,并不会触发附加的冲渲染过程。这里的$el对象已经修改,但是页面上的数据还没有发生改变。
updated
DOM结构上的数据已经完成更新。若再次修改data,会再次触发beforeUpdate、updated,进入死循环。
beforeDestroy
实例被销毁前调用,也就是说在这个阶段还是可以调用实例的。
实例的销毁,vue实例还是存在的,只是解绑事件的监听和数据与view的绑定,即数据驱动。
destroyed
实例被销毁后调用,所有的事件监听器已被移除,子实例被销毁。
这里再简单说一下父子组件的生命周期:
加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程:
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程:
父beforeUpdate->父updated
销毁过程:
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
总结
Vue的生命周期函数为开发者提供了非常便利的操作。但是善用生命周期才会不踩坑,掌握好Vue的生命周期是非常重要的。它能在很大程度上减少我们日常开发的BUG。
一定需要注意数据获取是个异步过程,而生命周期函数的运行是独立的!只要涉及到DOM更新的操作,推荐大家使用Vue的自带方法$nextTick。这个方法的意思是把回调函数内的操作延迟到下一个DOM更新循环之后。Vue本身会将所有DOM更新的操作放入一个队列里,$nextTick就是会将方法内回调函数的操作延迟到队列里下一个DOM更新后执行。