Vue2

理解 Vue 生命周期最好的方式是看图。下面用流程图展示 Vue 实例从创建到销毁的完整过程。

完整生命周期流程

                        ┌─────────────────────────────────────┐
                        │           new Vue()                 │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │         beforeCreate                │
                        │   实例初始化之前,data/methods 未定义  │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │      初始化 data、methods、computed   │
                        │         建立响应式系统               │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │           created                   │
                        │   实例创建完成,可访问 data/methods    │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │      是否有 el 选项?                 │
                        └──────────────────┬──────────────────┘
                                           │
                          ┌────────────────┴────────────────┐
                          │                                 │
                          ▼                                 ▼
                   ┌──────────────┐                  ┌──────────────┐
                   │     有 el     │                  │    无 el     │
                   └──────┬───────┘                  └──────┬───────┘
                          │                                 │
                          │                                 ▼
                          │                     ┌───────────────────────┐
                          │                     │  等待 vm.$mount(el)   │
                          │                     └───────────┬───────────┘
                          │                                 │
                          └────────────────┬────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │      是否有 template 选项?          │
                        └──────────────────┬──────────────────┘
                                           │
                          ┌────────────────┴────────────────┐
                          │                                 │
                          ▼                                 ▼
                   ┌──────────────┐                  ┌──────────────┐
                   │  有 template  │                  │ 无 template  │
                   │  编译 template │                  │ 使用 el HTML │
                   └──────┬───────┘                  └──────┬───────┘
                          │                                 │
                          └────────────────┬────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │         beforeMount                 │
                        │      模板编译完成,未挂载到 DOM       │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │      创建 vm.$el,替换 el           │
                        │         挂载到 DOM                  │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │           mounted                   │
                        │      DOM 挂载完成,可访问 $el        │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │          实例已挂载                 │
                        │      等待数据变化或销毁             │
                        └──────────────────┬──────────────────┘
                                           │
                          ┌────────────────┴────────────────┐
                          │                                 │
                          ▼                                 ▼
               ┌─────────────────────┐           ┌─────────────────────┐
               │     数据变化         │           │   vm.$destroy()     │
               └──────────┬──────────┘           └──────────┬──────────┘
                          │                                 │
                          ▼                                 ▼
               ┌─────────────────────┐           ┌─────────────────────┐
               │    beforeUpdate     │           │   beforeDestroy     │
               │  数据变化,DOM 未更新 │           │   实例即将销毁       │
               └──────────┬──────────┘           └──────────┬──────────┘
                          │                                 │
                          ▼                                 ▼
               ┌─────────────────────┐           ┌─────────────────────┐
               │    重新渲染虚拟 DOM   │           │   移除 watchers     │
               │      更新真实 DOM    │           │   移除子组件        │
               └──────────┬──────────┘           └──────────┬──────────┘
                          │                                 │
                          ▼                                 ▼
               ┌─────────────────────┐           ┌─────────────────────┐
               │      updated        │           │     destroyed       │
               │   DOM 更新完成       │           │    实例已销毁        │
               └──────────┬──────────┘           └────────────────┬────┘
                          │                                 │
                          │                                 ▼
                          │                     ┌─────────────────────┐
                          │                     │   实例生命周期结束   │
                          │                     └─────────────────────┘
                          │
                          └──────────────┐
                                         │
                                         ▼
                              返回等待数据变化状态

四个阶段详解

创建阶段

创建阶段主要完成实例的初始化工作:

beforeCreate
     │
     ▼
┌─────────────────────────────────┐
│  初始化事件 & 生命周期           │
│  初始化 data、props、methods     │
│  建立响应式绑定                  │
└─────────────────────────────────┘
     │
     ▼
  created

此阶段的特点:

  • beforeCreate:无法访问 data、methods
  • created:可以访问 data、methods,但不能访问 DOM

挂载阶段

挂载阶段将模板渲染成真实 DOM:

beforeMount
     │
     ▼
┌─────────────────────────────────┐
│  编译模板为渲染函数              │
│  生成虚拟 DOM                   │
│  创建真实 DOM                   │
│  替换页面中的 el 元素           │
└─────────────────────────────────┘
     │
     ▼
  mounted

此阶段的特点:

  • beforeMount:模板已编译,但未渲染到页面
  • mounted:DOM 已渲染完成,可以操作 DOM

更新阶段

当响应式数据变化时触发更新:

数据变化
     │
     ▼
beforeUpdate
     │
     ▼
┌─────────────────────────────────┐
│  重新生成虚拟 DOM               │
│  对比新旧虚拟 DOM (diff)        │
│  更新真实 DOM                   │
└─────────────────────────────────┘
     │
     ▼
  updated

此阶段的特点:

  • beforeUpdate:数据已更新,DOM 未更新
  • updated:DOM 已更新完成

销毁阶段

实例销毁时触发:

vm.$destroy()
     │
     ▼
beforeDestroy
     │
     ▼
┌─────────────────────────────────┐
│  移除 watchers                  │
│  移除事件监听器                  │
│  销毁子组件                     │
└─────────────────────────────────┘
     │
     ▼
  destroyed

此阶段的特点:

  • beforeDestroy:实例仍然可用,适合清理工作
  • destroyed:实例已销毁,所有绑定已移除

keep-alive 特殊钩子

使用 keep-alive 缓存的组件有额外的生命周期:

┌─────────────────────────────────────────────────┐
│                keep-alive 组件                   │
│                                                  │
│   首次创建:created → mounted → activated        │
│                                                  │
│   切换离开:deactivated                         │
│                                                  │
│   再次激活:activated                           │
│                                                  │
│   最终销毁:deactivated → beforeDestroy → destroyed │
└─────────────────────────────────────────────────┘

钩子说明:

钩子触发时机
activated组件被激活时
deactivated组件被缓存时
Vue.component('tab-content', {
  template: '<div>内容</div>',
  activated() {
    console.log('组件被激活,恢复状态')
    this.resumeFromCache()
  },
  deactivated() {
    console.log('组件被缓存,保存状态')
    this.saveToCache()
  }
})

错误处理钩子

Vue 还提供了错误捕获钩子:

new Vue({
  errorCaptured(err, vm, info) {
    console.error('错误:', err)
    console.error('组件:', vm)
    console.error('信息:', info)
    
    return false
  }
})

返回 false 可以阻止错误继续向上传播。