vue生命周期

生命周期可以分为四个阶段,初始化阶段,模板编译阶段,挂载阶段,已挂载和卸载阶段。

  •   el :选择器
  •   $el:对应选择器的template模板(html代码)
  •   render:也是vue实例中的一项,其参数更接近vue解析器,按优先级,render参数 > vue实例对象中有template > 外部的HTML模板 后面两个也是将其编译成render函数;【注意】render选项参数比template更接近Vue解析器!所以优先级如下:

     render函数选项  > template参数  > 外部HTML

  •   $mount :当Vue实例没有el属性时,则该实例尚没有挂载到某个dom中,假如需要延迟挂载,可以在之后手动调用vm.$mount()方法来挂载。例如:

         new Vue({内部无el项}).$mount('#app')是延迟加载,同下面的语句相同

         new Vue({el:"#app",***})

  1. computed计算属性可用于快速计算视图(View)中显示的属性。这些计算将被缓存,并且只在需要时更新.
  2. watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象,一般用于监控路由、input输入框的值特殊处理等等,它比较适合的场景是一个数据影响多个数据.
  3. methods每当触发重新渲染时,方法的调用方式将总是再次执行函数。因此,函数必须是一个纯函数。它不能有副作用。输出只能依赖于传递给函数的值。

HTML

<div id="app">
    <p>{{ message }}</p>
    <h1>{{message + '这是在outer HTML中的'}}</h1>
</div>

js

 var app = new Vue({
    el: '#app',
    data: {
        message : "xuxiao is boy"
    },
    template:"<h1>{{message +'这是在template中的'}}</h1>",
    // render: function(createElement) {
    //     return createElement('h1', 'this is createElement')
    // }
})

最终结果

20190520142852951.png
20190520142920131.png
20190520142946922.png

vue整个过程做了些什么

new Vue()创建实例

  1. vue项目都是通过组件化进行实现的,一个页面通过若干组件组成,构成一个组件树,
  2. 每一个组件都通过一个vue实例来进行管理,
  3. 每当要渲染一个组件前,都会为该组件创建一个vue实例来管理组件中的数据和事件方法。
  4. 通过new Vue()创建实例时,实际创建了一个vue实例的空壳,初始化生命周期和事件
注意:这时候实例中的data选项还没有数据,所以在beforecreated中无法访问到data中的数据

初始化阶段

beforecreate

  1. 在这个阶段,完成实例初始化,
  2. 初始化非响应式变量 this指向创建的实例;
  3. 可以在这加个loading事件;
  4. data computed watch methods上的方法和数据均不能访问,这个时候的Vue实例还什么都没有,
  5. $route对象是存在的,可以根据路由信息进行重定向之类的操作;
  6. 这个阶段的data对象未完成初始化,el也没有完成初始化;
  7. DOM还没有开始
注意:在beforecreated中千万不要去修改data中赋值的数据,最早也要在create里面去做(添加一些行为)

created 【创建完成】

在模板渲染成HTML前调用,即通常初始化一些属性值,然后再渲染成视图, 未挂载DOM;created时还没完成挂载,无法通过id等获得DOM元素;

  1. 实例创建完成 完成数据(data props computed)的初始化 导入依赖项。
  2. 可访问data computed watch methods上的方法和数据 ;
  3. 不能访问el【初始化还未完成】,ref为空数组 ;不能对元素进行操作;
  4. 可在这结束loading,
  5. 还做一些初始化,实现函数自执行,
  6. 可以对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。
  7. el还是undefined,
  8. 而数据已经与data中的属性进行绑定(放在data中属性当值发生改变的同时,视图也会发生变化),
  9. 在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取
  10. 若在此阶段进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中;因为created() 钩子函数执行的时候 DOM 其实并未进行任何渲染

    Vue.nextTick( [callback, context] ):在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

模板编译阶段

beforemount & mount

在created后,beforemount前,会检查el选项,没有就会调用vm.$mount(),然后就会继续检查template,没有的话就绑定el选项的html,进入beforemount后,编译模板为虚拟的DOM,,开始render,将虚拟DOM渲染到页面上;

从created到beforeMount的过程中,

     var app = new Vue({
            el: '#app',
            data: {
                message : "xuxiao is boy"
            },
            template:"<h1>{{message +'这是在template中的'}}</h1>",
            // render: function(createElement) {
            //     return createElement('h1', 'this is createElement')
            // },

首先会判断vue实例中有没有el选项,如果有的话则进行下面的编译,但是如果没有el选项,则停止生命周期,直到vue实例上调用vm.$mount(el)。

如果有el,再判断是否有template参数,如果有,则把其当作模板编译成render函数,
20190520143735512.png

如果没有,则把外部的html作为模板编译。template中的模板优先级高于outer HTML模板。

20190520143925157.png
这是把outerHTML当作模板编译了

<div id="app">

<p>{{ message }}</p>
<h1>{{message + '这是在outer HTML中的'}}</h1>

</div>

如果把实例中render function选项的注释去掉,则直接用render function里的,得到网页如下

2019052014420087.png

所以按优先级来说 render function>template>outerHTML
————————————————

在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX.
综合排名优先级:render函数选项 > template选项 > outer HTML.

挂载阶段

beforeMount【挂载之前】

在这个阶段,$el还只是我们在HTML里面写的节点。$el属性已存在,是虚拟dom,只是数据未挂载到模板中;有了el,编译了template|/outerHTML 能找到对应的template,并编译成render函数

  1. 载入前(完成了data和el数据初始化),
  2. 但是页面中的内容还是vue中的占位符
  3. $el属性已存在,是虚拟dom,只是数据未挂载到模板中。
  4. data中的message信息没有被挂在到Bom节点中,
  5. 在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

mounted 【成功挂载】

完成创建vm,

完成el的双向绑定,完成挂载dom和渲染,可以在这个阶段对挂载的DOM进行操作;

ref 可在这发起后端请求,拿回数据,配合路由钩子做一些事情; 可对DOM 进行操作

载入后html已经渲染(ajax请求可以放在这个函数中),把vue实例中的data里的message挂载到BOM节点中去

beforeUpdate

更新前状态(view层的数据变化前,不是data中的数据改变前),重新渲染之前触发,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染

  • 只有view上面的数据变化才会触发beforeUpdate和updated,仅属于data中的数据改变是并不能触发;
  • 数据更新之前 可在更新前访问现有的DOM,如手动移除添加的事件监听器;
  • beforeUpdate是指view层的数据变化前【具体的可以用this.$el.innerHTML可以看出没有改变】,不是data中的数据改变前触发。因为Vue是数据驱动的

updated

数据已经更改完成,dom也重新render完成【具体的可以用this.$el.innerHTML可以看出已经改变了

完成虚拟DOM的重新渲染和打补丁; 组件DOM 已完成更新; 可执行依赖的dom 操作 注意:不要在此函数中操作数据,会陷入死循环的。

当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher取而代之。

view层的数据更新后,data中的数据同beforeUpdate,都是更新完以后的。

注意:会发现beforeUpdateupdated钩子函数中的$el一样,根据官方理解beforeUpdate应该指向虚拟dom,所以才会一样,而dom中的真正内容不一样,但是beforeMountmouted钩子函数中为什么又会有区别呢?感觉是设计的不足之处。**_

activated

  • 在使用vue-router时有时需要使用来缓存组件状态,这个时候created钩子就不会被重复调用了,
  • 如果我们的子组件需要在每次加载的时候进行某些操作,可以使用activated钩子触发

deactivated

keep-alive 组件被移除时使用

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。
说明:

beforeDestroy(){
    console.group('beforeDestroy 销毁前状态==========>>');
    console.log("%c%s", "color:red", "el     : "+this.$el);   //[object HTMLDivElement]
    console.log(this.$el);
    console.log("%c%s", "color:red", "data   : "+this.$data); //[object Object]
    console.log("%c%s", "color:red", "message: "+this.message);   //今天周二了!!!
},


destroyed

官方解释:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

说明:执行destroy方法后,对data的改变不会再触发周期函数,此时的vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。

destroyed(){
    console.group('destroyed 销毁完成状态==========>>');
    console.log("%c%s", "color:red", "el     : "+this.$el);   //[object HTMLDivElement]
    console.log(this.$el);
    console.log("%c%s", "color:red", "data   : "+this.$data); //[object Object]
    console.log("%c%s", "color:red", "message: "+this.message);   //今天周二了!!!
},


具体使用

  • beforeCreate:这个时候data,watcher,methods统统没有,这个时候的Vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作。
  • 20190520144436609.png
  • 20190520144455848.png

mouted和created

20190520144542445.png

父子组件嵌套时触发钩子函数顺序

加载渲染过程

  父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件更新过程
  父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程
  父beforeUpdate->父updated

销毁过程
  父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

总结

  • beforecreate:可以在这加个loading事件
  • created :在这结束loading,还做一些初始化,实现函数自执行
  • mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
  • beforeDestory: 你确认删除vue实例了吗?
  • destoryed :当前实例已被销毁,解绑相关指令和事件监听器

参考文章:
https://blog.csdn.net/wasbb_mm/article/details/83861456
https://juejin.im/post/5c9f4fe36fb9a05e3a343a2c#heading-16
https://www.jianshu.com/p/7026b73bb626


素素
37 声望0 粉丝