Vue.js2.0生命周期的理解与应用

161 阅读3分钟

在学习vue2.x入门后,开始慢慢熟悉vue的模式和开发脚手架项目实践过程中,需要对生命周期钩子函数一定的理解,多少会用到这些钩子函数,根据自己的理解写了一下,欢迎指正或学习交流。

(一)vue2.x生命周期图

vue生命周期

(二)生命周期钩子函数说明

生命周期钩子函数 说明
beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer)属性初始化和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted el被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root实例挂载了一个文档内元素,当mounted被调用时 vm.$el 也在文档内。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

(三)代码演示

  1. 通过嵌套组件的页面加载查看显示顺序: 代码如下(可直接复制使用):

       <!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.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    
    <body>
        <div id="vue-app">
            <p>以下是调用组件信息</p>
            <div class="test">
                <keep-alive></keep-alive>
                <test-component v-bind:msg="msg" v-on:msgchange="updateMsg($event)"></test-component>
                </keep-alive>
            </div>
        </div>
    </body>
    <script>
        var child = {
            props: ['msg'],
            template: '<button v-on:click="changeChuanzhi">点击向父组件事件传值--{{msg}}</button>',
            methods: {
                changeChuanzhi: function () {
                    this.$emit("msgchange", "子组件向父组件传值"); //注意两个参数:第一个参数是事件名,第二个参数是传递的内容
                }
            },
            deactivated: function () {
                console.log('component deactivated!');
            },
            activated: function () {
                console.log('component activated');
            }
        };
    
        new Vue({
            el: '#vue-app',
            data: {
                msg: '父亲给儿子的信息'
            },
            methods: {
                updateMsg: function (msg) {
                    this.msg = msg;
                }
            },
            components: {
                'test-component': child
            },
    
            //生明周期示例
            beforeCreate: function () {
                alert("组件实例化之前执行的函数:beforeCreate()");
            },
            created: function () {
                alert("组件实例化完毕,但页面还未显示出来:created()");
            },
            beforeMount: function () {
                alert("组件挂载前,页面仍未展示,但虚拟DOM已经配置:beforeMount()");
            },
            mounted: function () {
                alert("组件挂载后,此方法执行后,页面显示:mounted()");
            },
            beforeUpdate: function () {
                alert("组件更新前,页面仍未更新,但虚拟DOM已经配置:beforeUpdate()");
            },
            updated: function () {
                alert("组件更新后,此方法执行后,页面显示:updated()");
            },
            beforeDestroy: function () {
                alert("组件销毁前:beforeDestroy()");
            },
            destroyed: function () {
                alert("组件销毁:destroyed()");
            },
    
        })
    </script>
    
    </html>

    运行结果:
    演示1

  2. 通过控制台查看页面加载显示顺序日志: 代码如下(可直接复制使用):

       <!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.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    
    <body>
        <div id="vue-app">
            <p>以下是调用组件信息</p>
            <div class="test">
                <p>默认显示的数据:{{msg}}</p>
                <test-component v-bind:msg="msg" v-on:msgchange="updateMsg($event)"></test-component>
            </div>
        </div>
    </body>
    <script>
        var child = {
            props: ['msg'],
            data: function () {
                return {
                    childtofather: '子组件向父组件传值'
                }
    
            },
            template: '<button v-on:click="changeChuanzhi">点击向父组件事件传值--{{msg}}</button>',
            methods: {
                changeChuanzhi: function () {
                    this.$emit("msgchange", this.childtofather); //注意两个参数:第一个参数是事件名,第二个参数是传递的内容
                }
            },
        };
    
        var app =new Vue({
            el: '#vue-app',
            data: {
                msg: '父亲给儿子的信息'
            },
            methods: {
                updateMsg: function (msg) {
                    this.msg = msg;
                }
            },
            components: {
                'test-component': child
            },
    
            //生明周期示例
            beforeCreate: function () {
                // alert("组件实例化之前执行的函数:beforeCreate()");
                console.group('beforeCreate 创建前状态===============》');
                var state1 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(state1);
            },
            created: function () {
                // alert("组件实例化完毕,但页面还未显示出来:created()");
                console.group('created 创建完毕状态===============》');
                var state2 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(state2);
            },
            beforeMount: function () {
                // alert("组件挂载前,页面仍未展示,但虚拟DOM已经配置:beforeMount()");
                console.group('beforeMount 挂载前状态===============》');
                var state3 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(this.$el);
                console.log(state3);
            },
            mounted: function () {
                // alert("组件挂载后,此方法执行后,页面显示:mounted()");
                console.group('mounted 挂载结束状态===============》');
                var state4 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
    
                }
                console.log(this.$el);
                console.log(state4);
            },
            beforeUpdate: function () {
                // alert("组件更新前,页面仍未更新,但虚拟DOM已经配置:beforeUpdate()");
                console.group('beforeUpdate 更新前状态===============》');
                var state5 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(this.$el);
                console.log(state5);
                debugger
            },
            updated: function () {
                // alert("组件更新后,此方法执行后,页面显示:updated()");
                console.group('updated 更新完成状态===============》');
                var state6 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
    
                }
                console.log(this.$el);
                console.log(state6);
            },
            beforeDestroy: function () {
                // alert("组件销毁前:beforeDestroy()");
                console.group('beforeDestroy 销毁前状态===============》');
                var state7 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(this.$el);
                console.log(state7);
            },
            destroyed: function () {
                // alert("组件销毁:destroyed()");
                console.group('destroyed 销毁完成状态===============》');
                var state8 = {
                    'el': this.$el,
                    'data': this.$data,
                    'msg': this.msg
                }
                console.log(this.$el);
                console.log(state8);
            },
    
        })
    </script>
    
    </html>

    简单说明一下结构:
    (1)创建了一个Vue根实例命名为vue-app,将其挂载到页面id为vue-app的dom元素上。
    (2)局部注册的一个组件child并在根实例中将其注册使其可以在根实例的作用域中使用。
    (3)将子组件用 包裹,为接下来的测试作准备。
    (4)打开开发者工具的控制台查看结果:
    运行结果

结果分析

1.beforeCreate执行时:data和el均未初始化,值为:undefined;
1
2.created执行时:Vue 实例观察的数据对象data已经配置好,已经可以得到vue-app.msg的值,但Vue 实例使用的根 DOM 元素el还未初始化;
2
3.beforeMount执行时:data和el均已经初始化,但从{{msg}}等页面展示数据可以看出此时el并没有渲染进数据,el的值为“虚拟”DOM的元素节点;
3

4.mounted执行时:此时el已经渲染完成并挂载到实例上,页面基本显示完成;
4

5.beforeUpdate执行时:会更新当前组件数据,但未在页面渲染出来;
5

6.updated执行时:会更新当前组件数据,并在页面渲染出来;
6

7.beforeDestroy和destroyed执行时:Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。注意:这里的销毁并不指代’抹去’,而是表示’解绑’。
7.1

验证一下,控制台输入:app.msg='super456' 页面{{msg}}并没有显示出来,结果显示:
7.2

(四)一些钩子函数应用

1.beforeCreate钩子中可以进行loading之类的动画加载;
2.在created钩子中可以对data数据进行操作,这个时候可以进行ajax请求将返回的数据赋给data,还可以进行网络接口的请求操作;
3.在mounted钩子对挂载的dom进行操作,也可以进行后台获取数据操作;

(五)文献参考

特别感谢:作者:hxgzj 的关于Vue.js2.0生命周期的研究与理解 这篇文章分析的很详细,看完后参考写了一个案例出来的。内容中也引用了很多。