超详细vue生命周期解析(详解)

超详细vue生命周期解析(详解)vue 是每一个前端开发人员都绕不过的一个技术 在国内的市场占有量也是非常的大 我们大部分人用着 vue 却不知道他内部其实经历了一些什么 每个生命周期又是什么时候开始执行的 我们今天来详细的看一看首先 生命周期是个啥 借用官网的一句话就是 每一个 vue 实例从创建到销毁的过程 就是这个 vue 实例的生命周期 在这个过程中 他经历了从开始创建 初始化数据 编译模板 挂载 Dom 渲染 更新 渲染 卸载等一系列过程 那么这些过程中 具体 vue 做了些啥 我们今天来了解一下 语述了解之前 我们先贴上一张官网的

vue是每一个前端开发人员都绕不过的一个技术,在国内的市场占有量也是非常的大,我们大部分人用着vue, 却不知道他内部其实经历了一些什么。每个生命周期又是什么时候开始执行的。我们今天来详细的看一看

首先,生命周期是个啥?
借用官网的一句话就是:每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期。在这个过程中,他经历了从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。那么这些过程中,具体vue做了些啥,我们今天来了解一下。

语述

  1. new Vue()实例化一个vue实例,然后init初始化event 和 lifecycle, 其实这个过程中分别调用了3个初始化函数(initLifecycle(), initEvents(), initRender()),分别初始化了生命周期,事件以及定义createElement函数,初始化生命周期时,定义了一些属性,比如表示当前状态生命周期状态得_isMounted ,_isDestroyed ,_isBeingDestroyed,表示keep-alive中组件状态的_inactive,而初始化event时,实际上就是定义了$once、$off、$emit、$on几个函数。而createElement函数是在初始化render时定义的(调用了initRender函数)
  2. 执行beforeCreate生命周期函数
  3. beforeCreate执行完后,会开始进行数据初始化,这个过程,会定义data数据,方法以及事件,并且完成数据劫持observe以及给组件实例配置watcher观察者实例。这样,后续当数据发生变化时,才能感知到数据的变化并完成页面的渲染
  4. 执行created生命周期函数,所以,当这个函数执行的时候,我们已经可以拿到data下的数据以及methods下的方法了,所以在这里,我们可以开始调用方法进行数据请求了
  5. created执行完后,我们可以看到,这里有个判断,判断当前是否有el参数(这里为什么需要判断,是因为我们后面的操作是会依赖这个el的,后面会详细说),如果有,我们再看是否有template参数。如果没有el,那么我们会等待调用$mount(el)方法(后面会详细说)。
  6. 确保有了el后,继续往下走,判断当有template参数时,我们会选择去将template模板转换成render函数(其实在这前面是还有一个判断的,判断当前是否有render函数,如果有的话,则会直接去渲染当前的render函数,如果没有那么我们才开始去查找是否有template模板),如果没有template,那么我们就会直接将获取到的el(也就是我们常见的#app,#app里面可能还会有其他标签)编译成templae, 然后在将这个template转换成render函数。
  7. 之后再调用beforMount, 也就是说实际从creted到beforeMount之间,最主要的工作就是将模板或者el转换为render函数。并且我们可以看出一点,就是你不管是用el,还是用template, 或者是用我们最常用的.vue文件(如果是.vue文件,他其实是会先编译成为template),最终他都是会被转换为render函数的。
  8. beforeMount调用后,我们是不是要开始渲染render函数了,首先我们会先生产一个虚拟dom(用于后续数据发生变化时,新老虚拟dom对比计算),进行保存,然后再开始将render渲染成为真实的dom。渲染成真实dom后,会将渲染出来的真实dom替换掉原来的vm.$el(这一步我们可能不理解,请耐心往下看,后面我会举例说明),然后再将替换后的$el append到我们的页面内。整个初步流程就算是走完了
  9. 之后再调用mounted,并将标识生命周期的一个属性_isMounted 置为true。所以mounted函数内,我们是可以操作dom的,因为这个时候dom已经渲染完成了。
  10. 再之后,只有当我们状态数据发生变化时,我们在触发beforeUpdate,要开始将我们变化后的数据渲染到页面上了(实际上这里是有个判断的,判断当前的_isMounted是不是为ture并且_isDestroyed是不是为false,也就是说,保证dom已经被挂载的情况下,且当前组件并未被销毁,才会走update流程)
  11. beforeUpdate调用之后,我们又会重新生成一个新的虚拟dom(Vnode),然后会拿这个最新的Vnode和原来的Vnode去做一个diff算,这里就涉及到一系列的计算,算出最小的更新范围,从而更新render函数中的最新数据,再将更新后的render函数渲染成真实dom。也就完成了我们的数据更新
  12. 然后再执行updated,所以updated里面也可以操作dom,并拿到最新更新后的dom。不过这里我要插一句话了,mouted和updated的执行,并不会等待所有子组件都被挂载完成后再执行,所以如果你希望所有视图都更新完毕后再做些什么事情,那么你最好在mouted或者updated中加一个$nextTick(),然后把要做的事情放在$netTick()中去做(至于为什么,以后讲到$nextTick再说吧)
  13. 再之后beforeDestroy没啥说的,实例销毁前,也就是说在这个函数内,你还是可以操作实例的
  14. 之后会做一系列的销毁动作,解除各种数据引用,移除事件监听,删除组件_watcher,删除子实例,删除自身self等。同时将实例属性_isDestroyed置为true
  15. 销毁完成后,再执行destroyed

示例

大致过程就是这样,下面我们来通过例子来看一看

<body> <div id="app"> <p>{ 
   { 
   message}}</p> <button @click="changeMsg">改变</button> </div> </body> <script> var vm = new Vue({ 
    el: '#app', data: { 
    message: 'hello world' }, methods: { 
    changeMsg () { 
    this.message = 'goodbye world' } }, beforeCreate() { 
    console.log('------初始化前------') console.log(this.message) console.log(this.$el) }, created () { 
    console.log('------初始化完成------') console.log(this.message) console.log(this.$el) }, beforeMount () { 
    console.log('------挂载前---------') console.log(this.message) console.log(this.$el) }, mounted () { 
    console.log('------挂载完成---------') console.log(this.message) console.log(this.$el) }, beforeUpdate () { 
    console.log('------更新前---------') console.log(this.message) console.log(this.$el) }, updated() { 
    console.log('------更新后---------') console.log(this.message) console.log(this.$el) } }) </script> 

从上面我们可以看出几点,

  • 首次,只执行了4个生命周期,beforeCreate,created, beforeMount, mounted。
  • 同时,我们可以看出,第一个生命周期中,我们拿不到data中的数据,因为这个时候数据还未初始化
  • created中,我们可以拿到data中的message数据了,因为初始化已经完成
  • beforeMount中,我们可以看出,我们拿到了$el,而mounted中,我们也拿到了$el, 不过好像有点不一样是吧。一个好像是渲染前的,一个是渲染后的。对的。看过MVVM响应式原来或者Vue源码你们就会发现,最初其实我们是会去让this.$el = new Vue时传入的那个el的dom。所以在beforMount中,其实我们拿到的就是页面中的#app。而再继续往后,首先我们是不是没有找到render函数啊,也没有找到template啊,所以他会怎么做啊,是不是会把我们的这个el(#app)编译成template模板啊,再转换为render函数,最后将render函数渲染成为真实dom,渲染成真实dom后,我们是不是会用这个渲染出来的dom去替换原来的vm.$el啊。这也就是我们前面所说到的替换$el是什么意思了。
  • 所以, 在mounted中,我们所得到的渲染完成后的$el。

下面我们再看个例子

var vm = new Vue({ 
    el: '#app', data: { 
    message: 'hello world' }, template: ' 
   
我是模板内的{ {message}}
'
, methods: { changeMsg () { this.message = 'goodbye world' } }, beforeCreate() { console.log('------初始化前------') console.log(this.message) console.log(this.$el) }, created () { console.log('------初始化完成------') console.log(this.message) console.log(this.$el) }, beforeMount () { console.log('------挂载前---------') console.log(this.message) console.log(this.$el) }, mounted () { console.log('------挂载完成---------') console.log(this.message) console.log(this.$el) }, beforeUpdate () { console.log('------更新前---------') console.log(this.message) console.log(this.$el) }, updated() { console.log('------更新后---------') console.log(this.message) console.log(this.$el) } })

在这里插入图片描述

mounted () { 
    console.log('------挂载完成---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) }, beforeUpdate () { 
    console.log('------更新前---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) }, updated() { 
    console.log('------更新后---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) } 

这么看是不是就很明了啦,beforeUpdate里面的$el的内容,确实还是改变之前的,而我们之前看到的,只是因为我们后面展开时指针指向了当前值才导致的,是个视觉差而已。

var vm = new Vue({ 
    data: { 
    message: 'hello world' }, // template: ' 
   
我是模板内的{ {message}}
',
methods: { changeMsg () { this.message = 'goodbye world' } }, beforeCreate() { console.log('------初始化前------') console.log(this.message) console.log(this.$el) }, created () { console.log('------初始化完成------') console.log(this.message) console.log(this.$el) }, beforeMount () { console.log('------挂载前---------') console.log(this.message) console.log(this.$el) }, mounted () { console.log('------挂载完成---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) }, beforeUpdate () { console.log('------更新前---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) }, updated() { console.log('------更新后---------') console.log(this.message) console.log(this.$el.innerHTML) console.log(this.$el) } })
export default new Vue({ 
    el: '#app', router, store, i18n, render: h => h(App) }) 

而有些vue项目中人家用的又是这样的

export default new Vue({ 
    router, store, i18n, render: h => h(App) }).$mount('#app') 

其实后者,就相当于是手动调用了$mount了。

好了,言尽于此,有没有看懂的朋友,请直接私信或者评论。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/177292.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午7:51
下一篇 2026年3月26日 下午7:51


相关推荐

  • Hunyuan-MT-7B多语翻译部署案例:vLLM加速+OpenWebUI界面,支持藏蒙维哈朝5种民族语

    Hunyuan-MT-7B多语翻译部署案例:vLLM加速+OpenWebUI界面,支持藏蒙维哈朝5种民族语

    2026年3月14日
    3
  • Java面试之Weblogic 及其它

    Java面试之Weblogic 及其它Java面试之Weblogic 及其它

    2022年4月22日
    44
  • WebApp开发实践

    WebApp开发实践网上购物网站(以出售软件为例)webApp开发由Java实现,运用了jdbc,jsp,servlet,jQueryFlot图表等技术,数据库为SqlServer2008,仅供参考学习,转载文章需注明:一、后台实现(1)用户的登入:(2)修改密码:(3)软件管理:(4)软件上新:(5)订单管理:(6)编辑公告:二、前台实现:(1)会员登录与注册模块:(2)搜索…

    2022年6月17日
    46
  • 成功实施结对编程

    成功实施结对编程成功实施结对编程 作者 JayFields 译者金毅 发布于 2009 年 5 月 31 日上午 5 时 21 分 社区 Agile 主题敏捷实施 敏捷技术标签结对编程在我做咨询工作的三年半时间里 我

    2026年3月18日
    2
  • spring boot 中使用 jpa以及jpa介绍

    最近在项目中使用了一下jpa,发现还是挺好用的。这里就来讲一下jpa以及在springboot中的使用。在这里我们先来了解一下jpa。1.什么是jpa呢?JPA顾名思义就是JavaPersistenceAPI的意思,是JDK5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。2.jpa具有什么优势?2.1标准化JPA是JCP组织发布的Java

    2022年4月5日
    56
  • (c语言)选择排序法和冒泡排序法

    (c语言)选择排序法和冒泡排序法问题描述:给定一个数组(或者输入一个数组),分别运用选择排序法和冒泡排序法将所要的结果输出。程序分析:                    选择排序1>.对于选择排序,首先理解排序的思想。给定一个数组,这种思想首先假定数组的首元素为最大(最小)的。此时就要利用3个变量i,j,k表示元素的下标。i表示当前,j表示找到的最大(最小)的下标,k用

    2022年6月25日
    27

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号