vue 父子组件的生命周期

1、vue的生命周期图

在vue实例的整个生命周期的各个阶段,会提供不同的钩子函数以供我们进行不同的操作。先列出vue官网上对各个钩子函数的详细解析。

生命周期钩子    

详细
beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
created

实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。

在执行data()方法前props属性有数据已经可以访问,watch和computed监听函数此时为null,此时this.computed里的计算属性值为undefined。data函数执行完后,watch和computed监听函数才可用,因为data函数执行完后,data函数return的属性这时才可用。然而,挂载阶段还没开始,$el 属性目前不可见。

beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
activated keep-alive 组件激活时调用。
deactivated keep-alive 组件停用时调用。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

2、实际操作 

下面我们在实际的代码执行过程中理解父子组件生命周期创建过程以及钩子函数执行的实时状态变化。

测试基于下面的代码,引入vue.js文件后即可执行。(打开页面后,再按一次刷新会自动进入debugger状态)

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7     <title>Document</title>
  8     <style>
  9         
 10     </style>
 11 </head>   
 12 <body>
 13 <div id="app">
 14     <p>{{message}}</p>
 15     <keep-alive>
 16         <my-components :msg="msg1" v-if="show"></my-components>
 17     </keep-alive>
 18 </div>
 19 </body>
 20 <script src="../../node_modules/vue/dist/vue.js"></script>
 21 <script>
 22     var child = {
 23         template: '<div>from child: {{childMsg}}</div>',
 24         props: ['msg'],
 25         data: function() {
 26             return {
 27                 childMsg: 'child'
 28             }   
 29         },
 30         beforeCreate: function () {
 31             debugger;
 32         },
 33         created: function () {
 34             debugger;
 35         },
 36         beforeMount: function () {
 37             debugger;
 38         },
 39         mounted: function () {
 40             debugger;
 41         },
 42         deactivated: function(){
 43             alert("keepAlive停用");
 44         },
 45         activated: function () {
 46             console.log('component activated');
 47         },
 48         beforeDestroy: function () {
 49             console.group('beforeDestroy 销毁前状态===============》');
 50             var state = {
 51                 'el': this.$el,
 52                 'data': this.$data,
 53                 'message': this.message
 54             }
 55             console.log(this.$el);
 56             console.log(state);
 57         },
 58         destroyed: function () {
 59             console.group('destroyed 销毁完成状态===============》');
 60             var state = {
 61                 'el': this.$el,
 62                 'data': this.$data,
 63                 'message': this.message
 64             }
 65             console.log(this.$el);
 66             console.log(state);
 67         },
 68     };
 69     var vm = new Vue({
 70         el: '#app',
 71         data: {
 72                 message: 'father',
 73                 msg1: "hello",
 74                 show: true
 75             },
 76         beforeCreate: function () {
 77             debugger;
 78         },
 79         created: function () {
 80             debugger;
 81         },
 82         beforeMount: function () {
 83             debugger;
 84         },
 85         mounted: function () {
 86             debugger;    
 87         },
 88         beforeUpdate: function () {
 89             alert("页面视图更新前");
 90             
 91         },
 92         updated: function () {
 93             alert("页面视图更新后");
 94         },
 95         beforeDestroy: function () {
 96             console.group('beforeDestroy 销毁前状态===============》');
 97             var state = {
 98                 'el': this.$el,
 99                 'data': this.$data,
100                 'message': this.message
101             }
102             console.log(this.$el);
103             console.log(state);
104         },
105         destroyed: function () {
106             console.group('destroyed 销毁完成状态===============》');
107             var state = {
108                 'el': this.$el,
109                 'data': this.$data,
110                 'message': this.message
111             }
112             console.log(this.$el);
113             console.log(state);
114         },
115         components: {
116             'my-components': child
117         }
118     });
119 </script>
120 </html>

3、小结

  • 加载渲染过程

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

  • 子组件更新过程

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

  • 父组件更新过程

  父beforeUpdate->父updated

  • 销毁过程

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

4、一些应用钩子函数的想法

  • 在created钩子中可以对data数据进行操作,这个时候可以进行ajax请求将返回的数据赋给data。
  • 虽然updated函数会在数据变化时被触发,但却不能准确的判断是那个属性值被改变,所以在实际情况中用computed或match函数来监听属性的变化,并做一些其他的操作。
  • 在mounted钩子对挂载的dom进行操作,此时,DOM已经被渲染到页面上。
  • 在使用vue-router时有时需要使用<keep-alive></keep-alive>来缓存组件状态,这个时候created钩子就不会被重复调用了,如果我们的子组件需要在每次加载或切换状态的时候进行某些操作,可以使用activated钩子触发。
  • 所有的生命周期钩子自动绑定 this 上下文到实例中,所以不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。这是导致this指向父级。

参考文章:https://www.cnblogs.com/yuliangbin/p/9348156.html

原文地址:https://www.cnblogs.com/zhilu/p/15251808.html