学习Vue,从了解Vue的生命周期开始

43 阅读4分钟

1.什么是Vue生命周期?

简单来说,Vue的生命周期就是描述一个Vue组件从引入到退出的全程。

详细来说,就是一个组件从开始创建初始化数据编译模板挂载DOM-渲染更新-渲染卸载等一些列过程。

2.Vue生命周期的执行顺序

Vue生命周期分为三大阶段,在这三大阶段中又分为若干小阶段。因此,我们可以在不同的阶段去做该阶段适合做的事。

image.png

详细执行顺序如下:

image.png

当通过new Vue()生成Vue示例对象时,生命周期钩子、事件开始初始化(beforeCreate)。接着进行数据监测和数据代理(Created),此时可以通过实例对象访问到data中的数据和methods中的方法,但DOM树还未挂载。然后Vue开始解析模板,先判断是否有el对象,无则挂载。再判断是否有模板,有则将模板转化为render函数,通过render函数去渲染创建dom树,无则编译el对象外层html作为模板,此时完成对虚拟DOM的生成(beforeMount);接着将次虚拟DOM转化为真实DOM渲染至页面,此时可进行DOM操作(mounted);当数据有被更新时,调用beforeUpdate,根据新数据生成新的虚拟DOM(diff算法对新旧DOM进行对比并操作...),最终完成页面的更新,页面和数据保持同步(updated);在实例销毁之前,data、methods等等都处于可用状态(beforeDestroy),然后清除watcher、子组件和事件监听器,组件销毁后调用(destroyed),组件确认已被销毁。

我们可以创建一个Vue实例来进行分析验证:

<body>
    <div id="root" :x="n">
        <h2 style="color:#42b883">Vue的生命周期</h2>
        <h3> 当前n的值是:{{n}}</h3>
        <button @click="add">点我n+1</button>
        <button @click="bye">点我销毁vm</button>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;
​
        const vm = new Vue({
            el: "#root",
            // template: `
            // <div>
            //     <h2> 当前n的值是:{{n}}</h2>
            //     <button @click="n++">点我n+1</button>
            // </div>`,
            data: {
                n: 1
            },
            beforeCreate() {
                console.log("%c%s", "color:red", '-------beforeCreate-------')
                console.log('$el:' + this.$el)
                console.log('$data:' + this.$data)
            },
            created() {
                console.log("%c%s", "color:red", '-------created-------')
                console.log('$el:' + this.$el)
                console.log('$data:' + this.$data)
            },
            beforeMount() {
                console.log("%c%s", "color:red", '-------beforeMount-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
            },
            mounted() {
                console.log("%c%s", "color:red", '-------mounted-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
                console.dir(this.$data)
            },
            beforeUpdate() {
                console.log("%c%s", "color:red", '-------beforeUpdate-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
                console.dir(this.$data)
            },
            updated() {
                console.log("%c%s", "color:red", '-------updated-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
                console.dir(this.$data)
            },
            beforeDestroy() {
                console.log("%c%s", "color:red", '-------beforeDestroy-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
                console.dir(this.$data)
            },
            destroyed() {
                console.log("%c%s", "color:red", '-------destroyed-------')
                console.log('$el:' + this.$el)
                console.dir(this.$el)
                console.log('$data:' + this.$data)
                console.dir(this.$data)
            },
            methods: {
                bye() {
                    console.log('bye')
                    this.$destroy()
                },
                add() {
                    this.n++
                }
            },
        })
    </script>
</body>

挂载阶段

image.png

我们可以看到,当页面一加载时,触发了beforeCreatecreatedbeforeMountmounted 这几个钩子。

最先进入beforeCreate,此时我们打印的el,data均为undefined。

接着进入created,此时el仍拿不到,但data已经加载进来了。

beforeMount时,此时已经生成虚拟DOM,但还未转化成真实DOM

image.png

mounted挂载结束,也就是虚拟DOM已经转化为真实DOM插入页面

image.png

更新阶段

我们点击n+1,可以看到:

image.png

进入更新阶段,触发beforeUpdateupdated这两个生命钩子

销毁阶段

点击销毁vm:

image.png

beforeDestroy,在销毁之前,el、data都是如同挂载之后的阶段一样,都是可以打印出来的。

destroyed完成销毁时,组件仍会打印未销毁状态时的el、data,但其定格未销毁时的最终形态,所有操作均无效。

生命周期的每个阶段适合做什么?

beforeCreate: 在Vue创建之前,data、computed、watch、methods上的方法和数据均不能访问,可以添加loading事件。。

created: 在Vue实例创建完毕状态,我们可以去访问data、computed、watch、methods上的方法和数据,但现在还没有将虚拟Dom挂载到真实Dom上,所以我们在此时访问不到我们的Dom元素。如果非要想与 Dom 进行交互,可以通过 vm.$nextTick 来访问 Dom。

我们在此时可以进行一些简单的Ajax,并可以对页面进行初始化之类的操作。

beforeMount: 它是在挂载之前被调用的,会在此时去找到虚拟Dom,并将其编译成Render。

mounted: 虚拟Dom已经被挂载到真实Dom上,此时我们可以获取Dom节点,$ref在此时也是可以访问的。

发送ajax请求、启动定时器、绑定自定义事件、订阅消息等(初始化操作)。

beforeUpdate: 响应式数据更新的时候会被调用,beforeupdate的阶段虚拟Dom还没更新,所以在此时依旧可以访问现有的Dom。

我们可以在此时访问现有的Dom,手动移除一些添加的监听事件。

updated: 此时补丁已经打完了,Dom已经更新完毕,可以执行一些依赖新Dom的操作。

但还是不建议在此时进行数据操作,避免进入死循环。

beforeDestroy: 在Vue实例销毁之前被调用,在此时我们的实例还未被销毁。

在此时可以做一些操作,比如销毁定时器,解绑全局事件,销毁插件对象等。

Vue3的生命周期

image.png

  • Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:

    • beforeDestroy改名为 beforeUnmount
    • destroyed改名为 unmounted

可以直接已配置项的形式使用生命周期钩子,也可以使用组合式API的形式使用,尽量统一

一般来说,组合式API里的钩子会比配置项的钩子先执行,组合式API的钩子名字有变化

  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:

    • beforeCreate===>setup()
    • created===>setup()
    • beforeMount ===>onBeforeMount
    • mounted===>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated===>onUpdated
    • beforeUnmount ===>onBeforeUnmount
    • unmounted ===>onUnmounted