祭出官方图: vue
Vue组件的生命周期主要为8个: beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。ajax
其实官方图已经讲明白不少了。包括各个阶段之间作了些什么事情,但在掌握上终归仍是有一些模糊的地方。api
下面作了一些梳理。数组
我的理解是主要分为三个阶段:app
如下代码vue分别注册了father和child组件,并在father中调用了child子组件来观察他们的生命周期已经前后关系:dom
<!-- HTML部分 --> <!-- 父组件挂载 --> <div id="app"></div> <!-- child模板 --> <div class="child" @click="updateTest()"> i'm child <br /> data: {{data}} </div> <!-- father模板 --> <div class="father"> <button @click="changeDate()">{{tData}}</button> <button @click="destroyEl()">destroy</button> <child v-if="showChild"></child> I'm father </div>
/*JavaScript部分*/ /*child*/ var child = Vue.extend({ template: '#child', data(){ return { data: 0 } }, methods:{ consoleinfo(){ console.log(this.data)}, updateTest(){ this.data += 1} }, beforeCreate(){ console.log('child-beforeCreate')}, created(){ console.log('child-created')}, beforeMount(){ console.log('child-beforeMount')}, mounted(){ console.log('child-mounted')}, beforeUpdate(){ console.log('child-beforeUpdate')}, updated(){ console.log('child-updated')}, beforeDestroy(){ console.log('child-beforeDestroy:') this.consoleinfo() }, destroyed(){ console.log('child-destroyed:') this.consoleinfo() } })
/*father*/ new Vue({ el: '#app', template:'#father', components:{child}, data(){ return { tData: 0, tCom: 'computed', showChild: true } }, computed:{ tComputed(){ return this.tCom} }, methods:{ consoleinfo(){ console.log('data: ' + this.tData) console.log('computed: ' + this.tComputed) console.log('el: ' + this.$el.outerHTML) }, changeDate(){ this.tData += 1 this.tCom = 'changeComputed' }, destroyEl(){ //this.showChild = false this.$destroy() } }, /** 建立阶段 */ beforeCreate(){ console.log('beforeCreate:') this.consoleinfo() }, created(){ console.log('created:') this.consoleinfo() }, beforeMount(){ console.log('beforeMount:') this.consoleinfo() }, mounted(){ console.log('mounted:') this.consoleinfo() }, /** 运行阶段 */ beforeUpdate(){ console.log('beforeUpdate:') this.consoleinfo() }, updated(){ console.log('updated:') this.consoleinfo() }, /** 注销阶段 */ beforeDestroy(){ console.log('beforeDestroy:') this.consoleinfo() }, destroyed(){ console.log('destroyed:') this.consoleinfo() } })
接下来看下各个生命周期控制台的输出:函数
在beforeCreate阶段以前,vue作了init初始化的操做。操做包括:this
—— 注册一些vue默认的属性方法事件(例如初始化vue的生命周期 —— 钩子beforeCreate()等)spa
所以,在beforeCreate钩子调用时,这些默认属性方法事件已经注册完成,可是vue实例中的data、computed、methods等都未定义:code
—— 图中函数consoleinfo(),报错“not a function”’
beforeCreate与Created之间,实例将定义的data、methods等初始化并进行注入。
所以在Created阶段,控制台已经可以输出data、computed值,包括控制台输出的方法methods,这些值都已在当前father组件实例中定义生成了。
—— 此时只是在js操做了vue实例,dom中的元素还并未挂载,所以实例的$el并不可以调用outerHTML,所以报错。
——(虽然father组件调用了child组件,可是此时子组件child生命周期还未开始!这里要注意,只是father组件作初始化。子组件实例的生命周期何时开始,接下来的father生命周期里会涉及)
—— 因为data数据、methods方法等在created中已被定义,此时已经能够去作一些ajax请求后台数据。
created与beforeMount之间,主要作了两步工做:
一、判断实例在dom中有没有挂载的元素(el:‘#app’),只有挂载了才可以继续。挂载好后,实例即与挂载dom元素进行了绑定(占坑),实例中也能够进行引用;
二、渲染dom模板。渲染dom模板只是在内存中,并不是是在HTML中的DOM结构中渲染,因此前台在这个阶段时,组件对应的元素是没有显示的。(在调用 this.$el.outerHTML 后,控制台输出 <div id="app"></div>)
—— 能够看到fathe组件的beforeMount时,child子组件的vue建立生命周期已经完成到mounted阶段。说明father在执行dom模板渲染的时候,会监测模板中是否有自定义的vue子组件。若是有,就进入子组件的生命周期的建立阶段,等到全部子组件的完成建立并挂载(mounted)到父组件的模板当中后。才能代表父组件在内存中的模板渲染完成。
—— 子组件的mounted阶段虽然完成,但父组件仍在beforeMounte阶段时。前台也看不见子组件渲染的效果,子组件只是完成了挂载到父组件的模板中了(控制台能够看到dom树中的元素并未变化)。所以此刻在子组件的mounted阶段直接调用一些方法(dom操做方法)可能会形成异常错误。为保险起见可在子组件中经过 $nextTick() 回调,等下一次DOM更新后再进行dom的操做。
—— 以上内存中渲染DOM能够了解一下Virtual DOM技术。
mounted阶段表示,当前实例在内存中渲染的组件模板,已成功挂在到父组件orDOM树中。
控制台能够看出DOM树中元素已经发生变化。
—— 这个阶段能够引用到元素,上面子组件提到过,一些状况下能够经过 $nextTick() 回调,避免一些意外错误。
经过点击左上角的button来改变father实例中的值
控制台
首先:只有实例中定义的变量绑定在了dom树中,例如 <div>{{data}}<div>,当data发生改变,才会进入beforeUpdate阶段。若dom树中未绑定某变量,该变量只在实例中发生变化,那么就不会进入beforeUpdate阶段!
我在代码中绑定了tData变量,从beforeUpdate阶段中能够看到,内部变量tData已经变化。页面中DOM的 tData绑定值还未变化。
子组件的数据更新,不会引发父组件的beforeUpdate和updated生命周期钩子。
beforeUpdate和updated阶段直接,vue根据变量更新后的数据在虚拟DOM中进行渲染(图中re-render)。
然后进行页面相应组件的更新。
控制台组件中值为1
若一个组件被判断为销毁,则进入相应的销毁阶段。通常状况下销毁阶段的调用有:
进入该阶段,代表实例已经接收到了被销毁的指令。
在该阶段,实例的属性、方法、事件等仍然能够调用。
在beforeDestroy与destroyed之间,组件开始注销本身的属性、方法、事件以及本身的子组件。只有等到全部都已注销完成(子组件达到destroyed阶段),父组件才可以进入destroyed阶段。看控制台。
以上注销方法,是经过 $destroy() 来进行的,能够看到调用该方法后,页面上的元素并未随vue实例注销。可是经过点击button已经没法改变其button数组,说明实例已经不存在。
—— $destroy只是彻底销毁一个实例。清理它与其它实例的链接,解绑它的所有指令及事件监听器。
—— 官方建议,$destroy 在多数状况下,仍是用 v-if 和 v-for 来替代