vue的生命周期

486 阅读3分钟

每个vue在被创建之前,都要经过一系列的初始化过程,这个过程就是vue的生命周期

在vue一整个生命周期中会员很多钩子函数提供给我们,再vue生命周期的不同时刻进行操作

vue父子生命周期执行顺序

  • 1,加载渲染过程

父子组件在加载的时候,执行的先后顺序为父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted。

  • 2,子组件更新过程

父beforeUpdate ---> 子beforeUpdate ---> 子updated ---> 父updated

  • 3,父组件更新过程

父beforeUpdate ---> 父updated

  • 4,销毁过程

父beforeDestroy ---> 子beforeDestroy ---> 子destroyed ---> 父destroyed

创建期间的生命周期函数

  1. beforeCreated

    在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用,还没有初始化好 data 和 methods 属性

  2. created

    在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用, 此时 data 和 methods 已经创建OK,此时还没有开始 编译模板

    在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调。 但是还没有开始 DOM 编译,$el 还不存在,但是实例存在,即this.a存在,可打印出来, 触发vue的created事件以后,this便指向vue实例

  3. beforMount

    在挂载开始之前被调用:相关的 render 函数首次被调用。此时已经完成了模板的编译,但是还没有挂载到页面中

    该钩子在服务器端渲染期间不被调用

  4. mounted

    实例被挂载后调用,这时 el 被新创建的 vm.el替换了。如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.el 也在文档内。

    注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick:

运行期间的生命周期函数

  1. beforUpdate

    数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

    该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

  2. updated

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

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

注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick:

销毁期间的生命周期函

  1. beforDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。 8. destroy

实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。该钩子在服务器端渲染期间不被调用 9. activated

被 keep-alive 缓存的组件激活时调用。该钩子在服务器端渲染期间不被调用

10. deactivated

被 keep-alive 缓存的组件停用时调用。
 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>vue生命周期学习</title>
  <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
  <div id="app">
    <h1>{{message}}</h1>
  </div>
</body>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue的生命周期'
    },
    beforeCreate: function() {
      console.group('------beforeCreate创建前状态------');
      console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
      console.log("%c%s", "color:red","message: " + this.message)  //undefined
    },
    created: function() {
      console.group('------created创建完毕状态------');
      console.log("%c%s", "color:red","el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 , [object Object]
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化, vue生命周期
    },
    beforeMount: function() {
      console.group('------beforeMount挂载前状态------');
      console.log("%c%s", "color:red","el     : " + (this.$el)); //undefined
      console.log(this.$el);//undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化, [object Object]
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化, vue生命周期
    },
    mounted: function() {
      console.group('------mounted 挂载结束状态------');
      console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
    },
    beforeUpdate: function () {
      console.group('beforeUpdate 更新前状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);//[object HTMLDivElement]
      console.log(this.$el);   
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    updated: function () {
      console.group('updated 更新完成状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el); 
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    beforeDestroy: function () {
      console.group('beforeDestroy 销毁前状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    destroyed: function () {
      console.group('destroyed 销毁完成状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);  
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message)
    }
  })
</script>
</html>

1,在beforCreated 和created钩子函数之间的生命周期

在这个生命周期之间,进行初始化时间,进行数据观测,可以看到在created的时候数据已经和data属性进行绑定(放在data中的属性当值发生改变的同事,视图也会改变)

注意:此时没有el

2,created钩子函数和beforeMount间的生命周期

在这个阶段发生的事情比较多

首先会判断对象是否有el选项,如果有就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el)

// 此时注释点代码
el: '#app'

可以看到运行到created的时候停止了,如果后面继续调用vm.$mount(el),可以发现代码继续向下执行了

vm.$mount(el) // 这个el参数就是挂载的dom节点

继续往下看,template参数选项是否对生命周期影响

  • 如果vue实例对象中有template参数选项,则将其作为模板编译成render函数
  • 如果没有template选项,则将外部HTML作为模板编译
  • 可以看到template中的模板优先级高于outer Html的优先级
// 修改vue中的代码

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

<script>
  var vm = new Vue({
    el: '#app',
    template: "<h1>{{message +'这是在 template 中的'}}</h1>" //在vue配置中修改的
    data: {
      message: 'Vue的生命周期'
    },

执行结果显示,vue的生命周期,这是在template中的,如果注释掉template的选项,则会显示出: vue的生命周期,这是在outer HTML中的

这样就可以知道为什么el的判断要在templa之前了,因为vue需要通过el找到对应的outer template

在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入jsx

new Vue({
	 el: '#app',
     render: function(createElement) {
     	return createElement('h1', 'this is createElement')
     }
})

可以看到页面渲染的是this is createElement

  • 所以综合排名优先级: render函数选项 > templa选项 > outer HTML

3, beforeMount 和 mounted狗子函数的生命周期

此时给vue实例添加$el成员,并且替换掉挂在的DOM元素

4,mounted

在mounted之前,h1中还是通过{{message}}占位的,因为此时还有挂载到页面上,还是js中的虚拟dom形式存在的,在mounted之后可以看到h1中内容发生了变化

5,beforeUpdate和updated钩子函数间的生命周期

当vue发现data中的数据发生了改变,会触发对应组件的重新渲染,先后调用beforeUpdate和updated

进入某个路由对应的组件的时候,我们会触发哪些类型的周期呢, 我们看到执行的顺序为

路由勾子 (beforeEach、beforeRouteEnter、afterEach)

根组件 (beforeCreate、created、beforeMount)

组件 (beforeCreate、created、beforeMount)

指令 (bind、inserted)

组件 mounted

根组件 mounted

beforeRouteEnter的next的回调

nextTick