VUE的生命周期

1.VUE的生命周期的简介

对于使用vue.js来开发,那我们就必须知晓vue的生命周期,才能愉快的玩耍,而且也是面试的高频,但是vue官方给出的文档,那叫一个简单啊,如下图:
在这里插入图片描述
但是,如果只是看上面的生命周期图,对于新手来说, 有点云里雾里,接下来,就是我对VUE的生命周期的理解.

2.VUE的生命周期的详情

Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等一系列过程,我们称为Vue实例的生命周期. 钩子函数,就是上图中,红色椭圆框那些,比如: beforeCreate, created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed这些.
钩子函数类似一个监听器,当Vue实例位于生命某个阶段时, 那对应的钩子函数就会被调用.那我们就可以编写对应的钩子函数, 让Vue在某个阶段给我们一个做某些处理的机会.我们理解Vue的生命周期,重点就是理解钩子函数的执行情况.

2.1 beforeCreate

beforeCreate函数是在实例初始化(new Vue())之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。也就是说, beforeCreate函数执行是在new Vue()这行代码执行,但是对Vue实例的属性还没有进行初始化的时候调用的,所有我们无法获取到在Vue实例中data定义的数据与在methods声明的函数,以及watcher中的事件都不能获得到. 废话不多说, 我们之间代码演示:

<div id="app"  >
    <input type="text" v-model="name" />
    欢迎:{{name}}
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript"></script>
<script type="text/javascript">
    const app = new Vue({
        el:'#app',
        data:{
            name:'zhangsan',
        },
        methods:{
            fun1(){
                console.log('fun1....');
            }
        },
        watch:{
            name(newVal, oldVal){
                console.log(newVal+"-->"+oldVal);
            }
        },
        beforeCreate(){
            console.log("组件实例化之前");
            console.log(this.name); 
            console.log(this.$el);
            this.fun1();

        }
    });

</script>

结果如下:
在这里插入图片描述
可以看到Vue中的data和方法都是去不到的

2.2 created

实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始, e l 属 性 目 前 不 可 见 。 也 就 是 V u e 实 例 的 初 始 化 完 成 , 在 这 个 钩 子 函 数 中 , 我 们 可 以 调 用 d a t a 中 的 数 据 , 以 及 m e t h o d s 的 函 数 , 但 是 我 们 还 无 法 获 取 el 属性目前不可见。也就是Vue实例的初始化完成,在这个钩子函数中,我们可以调用data中的数据,以及methods的函数,但是我们还无法获取 elVue,,data,methods,el对象,而且这个时候, 页面上的使用vue指令生成的标签也无法得到.

 <div id="app"  >
        <input type="text" v-model="name" />
        欢迎:{{name}}
        <ul>
            <li v-for="(item,index) of list" :key="index">{{item}}</li>
        </ul>

        <p v-text="num">p1</p>
        <p>p1</p>
        <p>p1</p>
    </div>
    <script type="text/javascript">
        const app = new Vue({
            el:'#app',
            data:{
                name:'zhangsan',
                list:[],
                num:0,
            },
            methods:{
                fun1(){
                    console.log('fun1....');
                }
            },
            watch:{
                name(newVal, oldVal){
                    console.log(newVal+"-->"+oldVal);
                }
            },
            created(){
                console.log("组件实例化完成");
                console.log(this.name);
                console.log(this.$el);
                this.fun1();
                //因为我们是通过v-for循环遍历li,所以created之前挂载阶段还没开始.是无法获取li的个数的
                console.log('li数量:',document.getElementsByTagName('li').length);
                //直接加载出来的DOM是可以直接获取到的
                console.log('p个数:',document.getElementsByTagName('p').length);
            },
        });
   </script>

结果:
在这里插入图片描述
可以看到:created钩子可以获取Vue的data,调用Vue方法,获取原本HTML上的直接加载出来的DOM,但是无法获取到通过挂载模板生成的DOM(例如:v-for循环遍历Vue.list生成li)

我们一般在create钩子函数中进行调用数据,调用方法,调用异步函数得加载数据的操作

2.3 beforeMount

在挂载开始之前被调用:相关的 render 函数首次被调用,这个时候,我们的$el已经创建,但是通过vue指令生成的标签还是无法获取到,因为我们还没有挂载到页面上.

 beforeMount(){
                console.log("组件挂载之前");
                console.log(this.name);
                console.log(this.$el);
                this.fun1();
                //因为我们是通过v-for循环遍历li,所以created之前挂载阶段还没开始.是无法获取li的个数的
                console.log('li数量:',document.getElementsByTagName('li').length);//获取的是页面初始标签, 通过vue生成的变化还没有挂载
                //直接加载出来的DOM是可以直接获取到的
                console.log('p个数:',document.getElementsByTagName('p').length);

            }

结果:
在这里插入图片描述
通过结果,我们发现 e l 现 在 有 值 了 , 说 明 el现在有值了,说明 el,el已经创建好了,但是li的数量还是1,不是3个,这是因为Vue生成的标签还没有挂载到页面

2.4 mounted

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
有初始值的DOM渲染,例如我们的初始数据list,渲染出来的li,只有这里才能获取.

  mounted(){
                console.log("组件挂载完成");
                console.log(this.name);
                console.log(this.$el);
                this.fun1();
                console.log('li数量:',document.getElementsByTagName('li').length);
                console.log('p个数:',document.getElementsByTagName('p').length);
            }

结果:
在这里插入图片描述

我们看到现在的li数量是3了,可以看到到这里为止,挂载到实例上了, 这时dom节点被渲染到文档内,一些需要dom的操作在此时才能正常进行,所以我们可以获取到li的个数了.

2.5 beforeUpdate

数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。这里需要注意的是beforeUpdate是在data数据被改变后触发,这里的data数据改变如何理解,仅从字面上理解只要data数据值改变就会触发beforeUpdate吗?答案是否定的,我们做个测试。

<div id="app"  >
    <input type="text" v-model="name" />
    欢迎:{{name}}
</div>
<script type="text/javascript">
    const app = new Vue({
        el:'#app',
        data:{
            name:'zhangsan',
            num : 0,
        },
       mounted(){
           console.log('组件加载完成');
           console.log('修改之前:num='+this.num);
           this.num++;
           console.log('修改之后:num='+this.num);
       },
        beforeUpdate(){
            console.log('组件更新之前');
            console.log('num='+this.num);
        }
    });

结果:
在这里插入图片描述
通过上面结果,我们发现beforeUpdate()函数并没有执行,这是为什么呢?
原因在于beforedate是针对视图层,视图层的数据发生改变才会触发, 而我们的num没有在页面标签使用,虽然num值改变了,但是,它也不会触发beforeUpdate()函数.那如果我们在标签使用这个num,那会不会触发beforeUpdate()函数呢?我们来做一个测试:
我们在页面添加如下代码:而js代码不做任何改变,我们再看一下结果会是怎么样?

<h1>{{num}}</h1>

结果:
在这里插入图片描述
此时,我们发现beforeUpdate()函数触发了,为什么这个时候,beforeUpdate()函数会触发呢? 这是因为我们在页面使用了这个num,也就是这个num属于视图层的数据,所以修改num,就会触发beforeUpdate()函数. 那如果我们把修改num的代码写在created()函数中, beforeUpdate()函数会触发吗? 大家思考一下.
答案是得分情况, 如果是直接修改的写法,肯定不会触发beforeUpdate()函数, 但是如果是异步加载数据,那这个时候,会触发beforeUpdate()函数,我们来测试一下:

const app = new Vue({
        el:'#app',
        data:{
            name:'zhangsan',
            num : 0,
        },
        methods:{
            fun1(){
                console.log('fun1....');
            }
        },
        created(){
           console.log('组件创建完成完成');
           console.log('修改之前:num='+this.num);
           setTimeout(()=>{ //使用setTimeout()来模拟异步修改
            this.num++;
            console.log('修改之后:num='+this.num);
           },0);
       },
        beforeUpdate(){
            console.log('组件更新之前');
            console.log('num='+this.num);
        }
    });

结果:
在这里插入图片描述
为什么这个beforeUpdate()函数又被触发了呢?
因为是在created的钩子中加入异步函数,所以函数的执行顺序为:
ceated钩子,mounted钩子,异步函数,beforeUpdate钩子,updated钩子,也就是异步函数是在mounted钩子之后执行的, 当mounted钩子执行后,这个num也就在页面使用了,然后在异步函数修改,就会触发.

2.7 updated

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。
我们在updated钩子中修改数据,也会触发beforeUpdate钩子.

 const app = new Vue({
        el:'#app',
        data:{
            name:'zhangsan',
            num : 0,
        },
        mounted(){
            console.log('组件挂载完成');
            console.log('修改前:num='+this.num);
            this.num=1;
            console.log('修改后:num='+this.num);
        },
        beforeUpdate(){
            console.log('组件更新之前');
            // console.log('修改前:num='+this.num);
            // this.num=2;
            // console.log('修改后:num='+this.num);
        },
        updated(){
            console.log('组件更新完成');
            console.log('修改前:num='+this.num);
            this.num=3;
            console.log('修改后:num='+this.num);
        }
    });

结果:
在这里插入图片描述
通过上面结果,我们发现beforeUpdate钩子调用了两次, 第一次是在挂载完成之后,调用mounted钩子函数, 此时在mounted函数修改了num,就触发了beforeUpdate, 当执行完beforeUpdate之后就执行updated钩子, 而我们在updated钩子函数中又一次修改了num,然后导致的虚拟 DOM 重新渲染和打补丁, 重新渲染页面的数据, 又触发了beforeUpdate钩子,所以第二次的beforeUpdate又被触发.
但是如果我们把上面代码中的beforeUpdate注释的代码放开, 你会发现,死循环了.
在这里插入图片描述
这是因为,当执行完updated钩子,而在updated()函数内部又修改了num,导致虚拟 DOM 重新渲染和打补丁, 重新渲染页面的数据, 又触发了beforeUpdate钩子, 而beforeUpdate钩子函数内又把num由3修改为2, 当beforeUpdate钩子执行完,就会执行updated钩子,而updated钩子又把num由2修改为3,导致虚拟 DOM 重新渲染和打补丁, 重新渲染页面的数据,从而又导致beforeUpdate触发…
所以就这样一直死循环下去,上面代码也可以把beforeUpdate钩子修改num的代码区别, 而把update修改num的代码修改为this.num++;此时也会是死循环.

应该避免在updated更改状态,因为这可能会导致更新无限循环

2.8 beforeDestroy

实例销毁之前调用。但是Vue实例仍然完全可用。

2.9 destroyed

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值