Vue父子组件生命周期执行顺序及钩子函数的理解

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

1. vue官网展示的vue的生命周期图

![img](https://gitee.com/quuer/storage/raw/master/20210312183415.png#pic_center =240x135)

在vue实例的整个生命周期的各个阶段,会提供不同的钩子函数以供我们进行不同的操作。

2. 生命周期钩子

生命周期 发生
beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。beforeUpdate数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
activated keep-alive 组件激活时调用。
deactivated keep-alive 组件停用时调用。
destroyed 实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
<!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>Document</title>    <style>    </style></head>   <body><div id="app">    <p>{{message}}</p>    <keep-alive>        <my-components :msg="msg1" v-if="show"></my-components>    </keep-alive></div></body><script src="./vue.js"></script><script>    var child = {        template: '<div>from child: {{childMsg}}</div>',        props: ['msg'],        data: function() {            return {                childMsg: 'child'            }           },        beforeCreate: function () {            debugger;        },        created: function () {            debugger;        },        beforeMount: function () {            debugger;        },        mounted: function () {            debugger;        },        deactivated: function(){            alert("keepAlive停用");        },        activated: function () {            console.log('component activated');        },        beforeDestroy: function () {            console.group('beforeDestroy 销毁前状态===============》');            var state = {                'el': this.$el,                'data': this.$data,                'message': this.message            }            console.log(this.$el);            console.log(state);        },        destroyed: function () {            console.group('destroyed 销毁完成状态===============》');            var state = {                'el': this.$el,                'data': this.$data,                'message': this.message            }            console.log(this.$el);            console.log(state);        },    };        var vm = new Vue({        el: '#app',        data: {                message: 'father',                msg1: "hello",                show: true            },        beforeCreate: function () {            debugger;        },        created: function () {            debugger;        },        beforeMount: function () {            debugger;        },        mounted: function () {            debugger;            },        beforeUpdate: function () {            alert("页面视图更新前");        },        updated: function () {            alert("页面视图更新后");        },        beforeDestroy: function () {            console.group('beforeDestroy 销毁前状态===============》');            var state = {                'el': this.$el,                'data': this.$data,                'message': this.message            }            console.log(this.$el);            console.log(state);        },        destroyed: function () {            console.group('destroyed 销毁完成状态===============》');            var state = {                'el': this.$el,                'data': this.$data,                'message': this.message            }            console.log(this.$el);            console.log(state);        },        components: {            'my-components': child        }    });</script></html>

3. 生命周期调试

首先我们创建了一个Vue实例vm,将其挂载到页面中id为“app”的元素上。

3.1 根组件的beforeCreate阶段

可以看出,在调用beforeCreate()函数时,只进行了一些必要的初始化操作(例如一些全局的配置和根实例的一些属性初始化),此时data属性为undefined,没有可供操作的数据。

3.2 根组件的Created阶段

调用Created()函数,在这一步,实例已完成以下的配置:数据代理和动态数据绑定(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

3.3 根组件的beforeMount阶段

在调用boforeMount()函数前首先会判断对象是否有el选项。如果有的话就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el)

在这个例子中,我们有el元素,因此会调用boforeMount()函数,此时已经开始执行模板解析函数,但还没有将$el元素挂载页面,页面视图因此也未更新。在标红处,还是 {{message}},这里就是应用的 Virtual DOM(虚拟Dom)技术,先把坑占住了。到后面mounted挂载的时候再把值渲染进去。

3.4子组件的beforeCreate、Created、beforeMount、Mounted阶段

在父组件执行beforeMount阶段后,进入子组件的beforeCreate、Created、beforeMount阶段,这些阶段和父组件类似,按下不表。beforeMount阶段后,执行的是Mounted阶段,该阶段时子组件已经挂载到父组件上,并且父组件随之挂载到页面中。

由下图可以知道,在beforeMount阶段之后、Mounted阶段之前,数据已经被加载到视图上了,即$el元素被挂载到页面时触发了视图的更新。

3.5 子组件的activated阶段

我们发现在子父组件全部挂载到页面之后被触发。这是因为子组件my-components被包裹,随$el的挂载被触发。如果子组件没有被<keep-alive>包裹,那么该阶段将不会被触发。

3.6 父组件的mounted阶段

mounted执行时:此时el已经渲染完成并挂载到实例上。

至此,从Vue实例的初始化到将新的模板挂载到页面上的阶段已经完成,退出debugger。下面我们来看一下deactivated、beforeUpdate、updated、beforeDestroy、destroyed钩子函数。

3.7 deactivated、beforeUpdate、updated阶段

由生命周期函数可知:当数据变化后、虚拟DOM渲染重新渲染页面前会触发beforeUpdate()函数,此时视图还未改变。当虚拟DOM渲染页面视图更新后会触发updated()函数。

我们不妨改变vm.show = false,当修改这个属性时,不仅会触发beforeUpdate、updated函数,还会触发deactivated函数(因为keep-alive 组件停用时调用)。我们不妨想一下deactivated函数会在beforeUpdate后还是updated后调用。

我们在控制台输入vm.show = false。得到三者的调用顺序分别为beforeUpdate、deactivated、updated。我们可以知道的是deactivated函数的触发时间是在视图更新时触发。因为当视图更新时才能知道keep-alive组件被停用了。

3.8 beforeDestroy和destroyed钩子函数间的生命周期

现在我们对Vue实例进行销毁,调用app.$destroy()方法即可将其销毁,控制台测试如下:

我们发现实例依然存在,但是此时变化已经发生在了其他地方。

beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。

destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁(也就是说子组件也会触发相应的函数)。这里的销毁并不指代'抹去',而是表示'解绑'。

销毁时beforeDestory函数的传递顺序为由父到子,destory的传递顺序为由子到父。

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

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

5. 小结

加载渲染过程

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

子组件更新过程

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

父组件更新过程

  父beforeUpdate->父updated

销毁过程
  父beforeDestroy->子beforeDestroy->子destroyed->父destroyed 

来源:https://www.icode9.com/content-4-888451.html

(0)

相关推荐

  • 18 vue 实例及其双向绑定的实现原理

    目录 一个vue实例 生命周期钩子函数 set/get 访问器属性的实现 v-model属性与{{text}}在模板中是如何被解析的? 观察者模式 源码 一个vue实例 一个典型的vue实例: < ...

  • 父组件监听子组件的生命周期

    如果父组件监听到子组件挂载mounted做一些逻辑处理 1.使用on和emit 子组件emit触发一个事件,父组件emit触发一个事件,父组件on监听相应事件. // Parent.vue <C ...

  • Vue3.x 从零开始(二)—— 重新认识 Vue 组件

    Vue 3 更新了许多组件中的语法,包括生命周期.filter.setup.teleport 等 为了介绍这些特性,需要先了解一下 Vue 组件的基本玩法 这篇文章介绍的内容基本都是沿用 Vue 2 ...

  • Vue生命周期,我奶奶看了都懂了

    最近一直在学习Vue,而vue生命周期是我们不可能绕开的一个很核心的知识点,今天来简单的梳理一下大概的内容. 一.钩子函数 在一开始学习的时候,总有钩子函数这个名词冒出来,而且在vue官网文档中也频繁 ...

  • vue3.0自定义指令(directives)

    在大多数情况下,你都可以操作数据来修改视图,或者反之.但是还是避免不了偶尔要操作原生 DOM,这时候,你就能用到自定义指令. 举个例子,你想让页面的文本框自动聚焦,在没有学习自定义指令的时候,我们可能 ...

  • Vue3.x 从零开始(三)—— 使用 Composition API 优化组件

    在<Vue3.x 从零开始(二)>中已经介绍了 Mixin 这种抽取公共逻辑的方式 但 Mixin 提供的数据或函数,无法在组件中直观的体现出来 这导致组件的维护人员需要非常熟悉被引入的 ...

  • vue父子组件状态同步的最佳方式续章(v-model篇)

    大家好!我是木瓜太香!一名前端工程师,之前写过一篇<vue父子组件状态同步的最佳方式>,这篇文章描述了大多数情况下的父子组件同步的最佳方式,也是被开源中国官方推荐了,在这里表示感谢! 这次 ...

  • vue父子组件状态同步的最佳方式

    哈喽!大家好!我是木瓜太香,一位老牌儿前端工程师,平时我们在使用 vue 开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面 ...

  • Android四大基本组件介绍与生命周期

    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity ...

  • vue之父子组件间通信实例讲解(props、$ref、$emit)

    组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.那么组件间如何通信,也就成为了vue中重点知识了.这篇文章将会通过props.$ref ...

  • 前端Vue(五)——Vue生命周期

    Vue生命周期 一.介绍 官方术语:生命周期钩子====>也是:生命周期函数 生命周期图网址:https://cn.vuejs.org/images/lifecycle.png Vue生命周期分 ...

  • Vue的options及生命周期

    6.Vue的options选项 options中可以包含哪些? 具体的详细解析可以查看这个地址: https://cn.vuejs.org/v2/api/#optionMergeStrategies ...

  • ​坚定不移地执行计划​并延长它的生命周期

    没错,我就是那个向生活低头的狗哥. 新年新气象,然后我就接了广告,并且赚够了未来一个月的电费.下一步的任务就是重新开始接顺风车,继续和你们分享不同的人生故事. 换了新的手机壁纸,2020年给自己的小目 ...