跳转到主要内容

主页内容

Vue基础(八)生命周期详解

由 webadmin 发布于 阅读 44 次

1、生命周期概述

什么是生命周期,从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件。而这些事件,被称为生命周期。

每个Vue实例在被创建时都要经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

比如created钩子可以用来在一个实例被创建之后执行代码:

<div id="root">
        
</div> 
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello'
            },
            created: function(){
                //this指向vm示例
                console.log("msg is "+ this.msg);
            }
        });
</script>

也有一些其它的钩子,在实例生命周期的不同阶段被调用,如:mountedupdateddestroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。

不要在选项属性或回调上使用箭头函数,比如:created:()=> console.log(this.a)vm.$watch('a',newvalue => this.myMethod())。因为箭头函数并没有 thisthis 会被当作变量一直向上级作用域查找,直至找到为止,经常导致 Uncaught TypeError:Cannot read property of undefinedUncaught TypeError:this.myMethod is not a function 之类的错误。

2、生命周期详解

2.1、生命周期图示

2.2、理解生命周期函数/钩子

生命周期钩子:即生命周期函数,也即是生命周期事件的别名而已。
主要的生命周期函数分类:

  • 创建/初始化阶段的生命周期函数(4个函数:beforeCreate()created()beforeMount()mounted());
  • 运行/更新阶段的生命周期函数(2个函数:beforeUpdate()updated());
  • 销毁阶段的生命周期函数(2个函数:beforeDestroy()destroyed());

2.3、生命周期函数执行流程

(1)、当引入vue.js之后,Vue就会成为全局变量,我们可以通过new Vue()创建一个Vue实例(创建Vue实例)
(2)、初始化事件和生命周期函数,没有执行(初始化Vue实例)
(3)、生命周期函数:beforeCreate(),在实例初始化之后,配置对象创建之前被调用
            表明:配置项都没有执行,datamethodscomputedfilters...都无法访问。
(4)、初始化、注入、校验,创建配置对象。
(5)、生命周期函数:created(),配置对象创建之后被调用。
            表明:datamethodscomputedfilters配置项都可以访问了。但是el,还没有绑定,vm实例挂载还没有开始。 created()生命周期函数中是最早可以操作data里面的数据的地方。
(6)、是否指定el配置项:
              是:继续向下执行
              否:判断是否调用vm.$mount(el),如果调用了才继续向下执行。
              要么指定了el配置项,要么调用了vm.$mount(el),否则必须继续向下执行。
(7)、是否指定了template选项:
              是:template编译到render函数中,使用template替代挂载点
              否:el外部的HTML作为template编译,把el挂载点作为template模板
(8)、生命周期函数:beforeMount():挂载开始之前被调用,此时,数据还没有被真正放到模板中,在这里还可以看到原始的模版数据,比如{{xxx}}...
(9)、创建vm.$el并用其替代el,用編译好的内容(指令和插值表达式替换后的内容)替代el挂载点里面的模版内容。
(10)、生命周期函数:mounted(),挂载完成之后调用,可以获取到真正渲染到页面中的真实数据。 mounted()是用到的最多的生命周期函数,用来发送一些异步请求。
(11)、经过上面一系列过程,脱离了创建阶段,挂载完毕。
(12)、生命周期函数:beforeUpdate(),实时监听数据变化(双向监听),一旦data中的数据发生改变(M/V)就会调用。到这里还没有进行数据的更新(ViewModel数据还没同步)。
(13)、虚拟DOM重新渲染,并应用更新。
(14)、生命周期函数:updated(),更新完成之后调用,DOMdata同步
(15)、档调用vm.$destroy()函数时,进行销毁阶段。
(16)、生命周期函数:beforeDestroy(),销毁之前。
(17)、解除绑定销毁子组件以及事件监听器。简单来说就是销毁Vue实例对象以及Vue里面的配置对象。
(18)、生命周期函数:destroyed(),销毁完毕。

3、生命周期函数使用

3.1、beforeCreate()函数执行

beforeCreate()是在创建配置对象之前调用,那么肯定无法使用datamethodscomputed...

<div id="root">
	{{msg}}
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            beforeCreate() {
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
            }
        });
    </script>

运行结果:

3.2、created()函数执行

配置对象创建之后调用,那么我们可以调用除了el以外的所有内容。

<div id="root">
	{{msg}}
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            created: function(){
                console.log("created()生命周期函数执行了");
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
                console.log("============created()生命周期函数执行结束了==========");
            },
        });
</script>

运行结果:

3.3、beforeMount()函数

beforeMount()是在挂载之前被调用,编译之后的模版还没有替换挂载点里面的内容。

<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            beforeMount() {
                console.log("beforeMount()生命周期函数执行了");
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
                console.log("============beforeMount()生命周期函数执行结束了==========");
            },
        });
</script>

运行结果:

3.4、mounted()函数

mounted()实例挂载完成后执行。

<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            //挂载完成
            mounted() {
                console.log("mounted()生命周期函数执行了");
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
                let html = document.getElementById("root").innerHTML;
                console.log(html);
                console.log("============mounted()生命周期函数执行结束了==========");
            },

        });
</script>

运行结果:

3.5、beforeUpdate()函数

  • 页面刷新,数据没有发生改变,该函数不会执行,只有当data发生改变后,才会进入该函数;
  • 表示data中的数据已经被更新,但是你仅更新了内存中的vm,还没有更新到DOM树;
  • 可以访问datamethod,可以访问到最新的值;
  • DOM中的元素的值,也可以被访问到,但是获取的是改变之前的旧值;
  • Vue实例处于运行阶段;
<div id="root">
            <p>{{msg}}</p>
            <button @click="modifyMsg">修改msg</button>
</div> 
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                },
                modifyMsg(){
                    this.msg = 'msg修改后的数据';
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            //更新数据之前
            beforeUpdate(){
                console.log("beforeUpdate()生命周期函数执行了");
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
                let html = document.getElementById("root").innerHTML;
                console.log(html);
                console.log("============beforeUpdate()生命周期函数执行结束了==========");
            }

        });
</script>

档点击修改msg按钮的时候,beforeUpdate()函数执行,执行结果:

3.6、updated函数

  • 表示dataDOM树的数据都是最新的;
  • 可以访问datamethodsDOM元素的值可以访问到最新值;
  • Vue实例处于运行阶段;

当更新完成后,执行updated,数据已经更改完成,DOM也重新render完成。

<div id="root">
            <p>{{msg}}</p>
            <button @click="modifyMsg">修改msg</button>
</div> 

<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                msg: 'Hello Vuejs'
            },
            methods: {
                fn1(){
                    console.log("methods里面的函数fn1执行了......")
                },
                modifyMsg(){
                    this.msg = 'msg修改后的数据';
                }
            },
            computed:{
                reverseMsg(){
                    return this.msg.split('').reverse().join('');
                }
            },
            //在vue实例里面显式定义生命周期函数
            //更新数据之后
            updated(){
                console.log("updated()生命周期函数执行了");
                console.log("data里面的数据: "+ this.msg);
                console.log("计算属性中的数据: "+ this.reverseMsg);
                //methods里面的函数
                this.fn1();
                let html = document.getElementById("root").innerHTML;
                console.log(html);
                console.log("============updated()生命周期函数执行结束了==========");
            }

        });
</script>

运行结果:

3.7、beforeDestory()和destoryed()

       当经过某种途径调用$destroy()方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等。

      当执行beforeDestory()方法时,Vue实例就已经从运行阶段,进入到了销毁阶段;组件的数据绑定、监听..去掉后只剩下DOM空壳,这个时候,执行destroyed,在这里做善后工作也可以。当执行beforeDestory()的时候,实例身上所有的datamethods以及过滤器、指令等都处于可用状态,此时,还没有真正执行销毁过程。当执行到destroyed()方法时,Vue组件里的过滤器、指令、方法都不可用了。

3、常用生命周期方法

created()/mounted():发送ajax请求,启动定时器等异步任务;
beforeDestory():做收尾工作,如:清除定时器;