Skip to content

Vue 2 生命周期详解

什么是 Vue 生命周期

Vue 生命周期是指 Vue 实例从创建到销毁的整个过程,在此过程中会触发一系列的钩子函数(生命周期钩子)。这些钩子函数允许我们在不同阶段执行特定的操作,从而更好地控制和管理 Vue 实例。

Vue 2 生命周期钩子

1. 创建阶段

beforeCreate

  • 执行时机:Vue 实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前。
  • 作用:此时实例的属性和方法尚未初始化,无法访问 datacomputedmethods 等。
  • 使用场景:通常用于初始化非响应式数据,或执行一些与 Vue 实例无关的操作。
javascript
new Vue({
  beforeCreate() {
    console.log('beforeCreate 钩子执行')
    console.log('data:', this.message) // undefined
    console.log('methods:', this.changeMessage) // undefined
  },
  data: {
    message: 'Hello Vue!'
  },
  methods: {
    changeMessage() {
      this.message = 'Hello World!'
    }
  }
})

created

  • 执行时机:Vue 实例创建完成后执行,此时已完成数据观测、属性和方法的运算,以及 event/watcher 的回调。
  • 作用:可以访问 datacomputedmethods 等,但 DOM 尚未生成,$el 属性不可用。
  • 使用场景:适合进行数据初始化、发起异步请求(如 API 调用)、设置监听器等操作。
javascript
new Vue({
  created() {
    console.log('created 钩子执行')
    console.log('data:', this.message) // 'Hello Vue!'
    console.log('methods:', this.changeMessage) // 函数定义
    // 发起异步请求
    axios.get('/api/data').then(response => {
      this.data = response.data
    })
  },
  data: {
    message: 'Hello Vue!',
    data: {}
  },
  methods: {
    changeMessage() {
      this.message = 'Hello World!'
    }
  }
})

2. 挂载阶段

beforeMount

  • 执行时机:在挂载开始之前执行,此时模板已编译完成,但尚未挂载到 DOM 上。
  • 作用:可以获取编译后的模板,但 DOM 尚未更新。
  • 使用场景:可用于最后一次修改模板数据的机会。
javascript
new Vue({
  beforeMount() {
    console.log('beforeMount 钩子执行')
    console.log('$el:', this.$el) // 已存在但未挂载
    // 最后一次修改数据
    this.message = '修改后的消息'
  },
  data: {
    message: 'Hello Vue!'
  }
})

mounted

  • 执行时机:挂载完成后执行,此时 Vue 实例已挂载到 DOM 上,$el 属性可用。
  • 作用:可以访问和操作 DOM 元素,执行依赖于 DOM 的操作。
  • 使用场景:适合初始化需要 DOM 的第三方库(如图表库、地图库)、绑定事件监听器等。
javascript
new Vue({
  mounted() {
    console.log('mounted 钩子执行')
    console.log('$el:', this.$el) // 已挂载到 DOM
    // 初始化第三方库
    this.initChart()
  },
  methods: {
    initChart() {
      // 假设使用 ECharts
      const chart = echarts.init(this.$el.querySelector('#chart'))
      chart.setOption({
        // 配置项
      })
    }
  }
})

3. 更新阶段

beforeUpdate

  • 执行时机:数据更新后,DOM 更新前执行。
  • 作用:可以获取更新前的 DOM 状态,或执行一些在 DOM 更新前需要的操作。
  • 使用场景:适合在数据变化但 DOM 未更新时进行操作,如获取更新前的 DOM 尺寸、位置等。
javascript
new Vue({
  beforeUpdate() {
    console.log('beforeUpdate 钩子执行')
    console.log('更新前的 DOM 内容:', this.$el.textContent)
  },
  data: {
    message: 'Hello Vue!'
  }
})

updated

  • 执行时机:DOM 更新完成后执行。
  • 作用:可以获取更新后的 DOM 状态,执行依赖于 DOM 更新的操作。
  • 使用场景:适合在 DOM 更新后执行操作,如重新计算 DOM 尺寸、位置,或更新第三方库的配置。
javascript
new Vue({
  updated() {
    console.log('updated 钩子执行')
    console.log('更新后的 DOM 内容:', this.$el.textContent)
    // 重新计算 DOM 尺寸
    this.calculateSize()
  },
  methods: {
    calculateSize() {
      const height = this.$el.offsetHeight
      console.log('元素高度:', height)
    }
  }
})

4. 销毁阶段

beforeDestroy

  • 执行时机:Vue 实例销毁前执行,此时实例仍完全可用。
  • 作用:可以执行清理操作,如清除定时器、取消事件监听器、解绑第三方库等。
  • 使用场景:适合进行资源释放,避免内存泄漏。
javascript
new Vue({
  beforeDestroy() {
    console.log('beforeDestroy 钩子执行')
    // 清除定时器
    clearInterval(this.timer)
    // 取消事件监听器
    window.removeEventListener('resize', this.handleResize)
  },
  mounted() {
    this.timer = setInterval(() => {
      console.log('定时器执行')
    }, 1000)
    window.addEventListener('resize', this.handleResize)
  },
  methods: {
    handleResize() {
      console.log('窗口大小变化')
    }
  }
})

destroyed

  • 执行时机:Vue 实例销毁后执行,此时实例的所有指令已解绑,事件监听器已移除,子实例也已销毁。
  • 作用:可以执行最终的清理操作。
  • 使用场景:通常用于确认实例已完全销毁,或执行一些与实例销毁相关的最终操作。
javascript
new Vue({
  destroyed() {
    console.log('destroyed 钩子执行')
    console.log('实例已销毁')
  }
})

5. 特殊生命周期钩子

activated

  • 执行时机:当使用 keep-alive 包裹的组件被激活时执行。
  • 作用:可以在组件被激活时执行操作。
  • 使用场景:适合在组件被重新激活时进行数据刷新或状态重置。
javascript
new Vue({
  activated() {
    console.log('activated 钩子执行')
    // 刷新数据
    this.fetchData()
  },
  methods: {
    fetchData() {
      // 重新获取数据
    }
  }
})

deactivated

  • 执行时机:当使用 keep-alive 包裹的组件被停用时执行。
  • 作用:可以在组件被停用时执行清理操作。
  • 使用场景:适合在组件被停用时保存状态或执行清理。
javascript
new Vue({
  deactivated() {
    console.log('deactivated 钩子执行')
    // 保存状态
    this.saveState()
  },
  methods: {
    saveState() {
      // 保存当前状态
    }
  }
})

生命周期执行顺序

Vue 实例的生命周期执行顺序如下:

  1. 创建阶段beforeCreatecreated
  2. 挂载阶段beforeMountmounted
  3. 更新阶段beforeUpdateupdated(数据变化时触发)
  4. 销毁阶段beforeDestroydestroyed(实例销毁时触发)
  5. 特殊阶段activated(组件被激活时触发)→ deactivated(组件被停用时触发)

生命周期钩子的使用建议

1. 数据初始化和异步请求

  • created:适合进行数据初始化、发起异步请求(如 API 调用)。
  • 原因:此时已可访问 datamethods,但 DOM 尚未挂载,避免了不必要的 DOM 操作。

2. DOM 操作和第三方库初始化

  • mounted:适合执行依赖于 DOM 的操作,如初始化第三方库(图表、地图等)。
  • 原因:此时 DOM 已挂载,可直接访问和操作 DOM 元素。

3. 数据更新前后的操作

  • beforeUpdate:适合在 DOM 更新前获取状态,如获取更新前的 DOM 尺寸。
  • updated:适合在 DOM 更新后执行操作,如重新计算尺寸或更新第三方库。

4. 资源清理

  • beforeDestroy:适合执行清理操作,如清除定时器、取消事件监听器、解绑第三方库。
  • 原因:此时实例仍可用,可以访问需要清理的资源。

5. 组件激活和停用

  • activated:适合在组件被激活时刷新数据或重置状态。
  • deactivated:适合在组件被停用时保存状态或执行清理。

示例:完整的生命周期演示

javascript
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!',
    count: 0
  },
  beforeCreate() {
    console.log('1. beforeCreate: 实例初始化前')
    console.log('data:', this.message) // undefined
  },
  created() {
    console.log('2. created: 实例创建完成')
    console.log('data:', this.message) // 'Hello Vue!'
    // 发起异步请求
    setTimeout(() => {
      this.message = '从 API 获取的数据'
    }, 1000)
  },
  beforeMount() {
    console.log('3. beforeMount: 挂载前')
    console.log('$el:', this.$el)
  },
  mounted() {
    console.log('4. mounted: 挂载完成')
    console.log('$el:', this.$el)
    // 初始化定时器
    this.timer = setInterval(() => {
      this.count++
    }, 1000)
  },
  beforeUpdate() {
    console.log('5. beforeUpdate: 更新前')
    console.log('count:', this.count)
  },
  updated() {
    console.log('6. updated: 更新完成')
    console.log('count:', this.count)
  },
  beforeDestroy() {
    console.log('7. beforeDestroy: 销毁前')
    // 清除定时器
    clearInterval(this.timer)
  },
  destroyed() {
    console.log('8. destroyed: 销毁完成')
  }
})

总结

Vue 2 的生命周期钩子提供了在不同阶段执行操作的能力,使我们能够更好地控制和管理 Vue 实例。通过合理使用这些钩子,我们可以:

  • 在适当的时机初始化数据和发起请求
  • 执行依赖于 DOM 的操作和第三方库初始化
  • 在数据更新前后执行相应的操作
  • 及时清理资源,避免内存泄漏
  • 处理组件的激活和停用状态

理解和掌握 Vue 2 的生命周期,对于构建高效、可维护的 Vue 应用至关重要。在实际开发中,应根据具体需求选择合适的生命周期钩子来执行相应的操作,以确保应用的性能和稳定性。

基于 VitePress 的本地知识库