Vue 生命周期钩子详解

生命周期钩子简介

生命周期钩子是Vue提供的一系列函数,让开发者可以在组件不同阶段添加自定义代码。比如组件创建时、挂载到DOM时、数据更新时或组件销毁时执行特定操作。

什么是生命周期?

Vue组件从创建到销毁的整个过程称为生命周期。在此过程中,Vue实例会经历一系列的初始化步骤——例如设置数据监听、编译模板、挂载实例到DOM、在数据变化时更新DOM等。

什么是钩子函数?

钩子函数就是在特定时间点自动执行的函数。Vue为开发者提供了多个钩子函数,允许我们在特定阶段运行自己的代码。

为什么需要了解生命周期?

  1. 控制执行时机:某些操作需要在特定时刻执行,如DOM加载完成后才能操作DOM元素
  2. 资源管理:合理利用创建和销毁钩子进行资源申请和释放
  3. 性能优化:了解各阶段特性可以避免重复渲染和不必要的计算
  4. 调试能力:了解生命周期有助于定位和解决问题

Vue生命周期图解

Vue的生命周期可以分为四个主要阶段:创建挂载更新销毁

┌─────────────────────┐
│  创建阶段           │
│  beforeCreate       │ ← 实例创建前,data和methods都不可用
│  created            │ ← 实例创建后,data和methods可用,但DOM未挂载
└─────────────────────┘
          ↓
┌─────────────────────┐
│  挂载阶段           │
│  beforeMount        │ ← DOM挂载前,template已编译但未渲染到页面
│  mounted            │ ← DOM挂载后,可访问DOM元素
└─────────────────────┘
          ↓
┌─────────────────────┐
│  更新阶段           │
│  beforeUpdate       │ ← 数据更新前,DOM更新前
│  updated            │ ← 数据更新后,DOM更新后
└─────────────────────┘
          ↓
┌─────────────────────┐
│  销毁阶段           │
│  beforeUnmount      │ ← 组件卸载前(Vue 3)/beforeDestroy(Vue 2)
│  unmounted          │ ← 组件卸载后(Vue 3)/destroyed(Vue 2)
└─────────────────────┘

创建阶段钩子

beforeCreate

在实例初始化之后,数据观测(data observer)和事件配置(event/watcher)之前被调用。

特点

  • 此时无法访问组件的数据(data)和方法(methods)
  • 不能操作DOM,因为组件还未挂载
  • 通常用于插件开发和全局配置

示例

export default {
  beforeCreate() {
    console.log('beforeCreate钩子执行了');
    console.log('能否访问data:', this.message === undefined);
    console.log('能否访问methods:', this.sayHello === undefined);
  },
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  methods: {
    sayHello() {
      console.log(this.message);
    }
  }
}

适用场景

  • 设置组件的初始化逻辑,但不依赖于data和DOM
  • 插件内部初始化
  • 设置应用级别的配置

created

在实例创建完成后被立即调用。此时已完成数据观测、计算属性、方法、事件/侦听器的配置。

特点

  • 可以访问组件的数据(data)和方法(methods)
  • 无法访问DOM,因为组件还未挂载
  • 常用于数据初始化和API调用

示例

export default {
  data() {
    return {
      users: [],
      loading: true
    }
  },
  created() {
    console.log('created钩子执行了');
    console.log('能否访问data:', this.loading);
    
    // 在组件创建后立即获取数据
    this.fetchUsers();
  },
  methods: {
    async fetchUsers() {
      try {
        const response = await fetch('https://api.example.com/users');
        this.users = await response.json();
      } catch (error) {
        console.error('获取用户数据失败:', error);
      } finally {
        this.loading = false;
      }
    }
  }
}

适用场景

  • 发起API请求获取初始数据
  • 设置初始状态
  • 基于props进行数据处理
  • 注册全局事件监听器

挂载阶段钩子

beforeMount

在挂载开始之前被调用:相关的render函数首次被调用。

特点

  • 模板已经编译完成,但还没有渲染到页面上
  • 虚拟DOM已创建,但未挂载到实际DOM中
  • 此时仍不能操作DOM元素

示例

export default {
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  beforeMount() {
    console.log('beforeMount钩子执行了');
    console.log('DOM元素是否可访问:', document.getElementById('app') === null);
    console.log('当前数据:', this.message);
  }
}

适用场景

  • 需要在DOM渲染前最后一次修改数据状态
  • 访问props和data数据,但不需要访问DOM
  • 服务端渲染相关的处理

mounted

在实例挂载到DOM后调用,此时可以访问DOM元素。

特点

  • 组件的DOM已完全渲染
  • 可以执行依赖于DOM的操作
  • 子组件的mounted也已经完成
  • 常用于DOM操作、第三方库初始化和数据获取

示例

export default {
  data() {
    return {
      chartData: [30, 50, 20, 40, 90]
    }
  },
  mounted() {
    console.log('mounted钩子执行了');
    console.log('DOM元素可访问:', document.getElementById('chart') !== null);
    
    // 初始化图表库
    this.initChart();
    
    // 添加窗口调整事件监听
    window.addEventListener('resize', this.handleResize);
  },
  methods: {
    initChart() {
      const chartEl = document.getElementById('chart');
      if (!chartEl) return;
      
      // 使用第三方库初始化图表
      const myChart = new Chart(chartEl, {
        type: 'bar',
        data: {
          datasets: [{
            data: this.chartData
          }]
        }
      });
    },
    handleResize() {
      // 窗口大小变化时重新调整图表大小
      console.log('窗口大小已改变,调整图表尺寸');
    }
  },
  beforeUnmount() {
    // 移除事件监听器,避免内存泄漏
    window.removeEventListener('resize', this.handleResize);
  }
}

适用场景

  • 初始化需要DOM的第三方库(如图表、地图等)
  • 添加全局事件监听
  • 获取DOM元素信息和尺寸
  • 执行DOM操作(如滚动到特定位置)
  • 发送依赖于DOM的数据请求

更新阶段钩子

beforeUpdate

数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。

特点

  • 数据已更新,但DOM尚未更新
  • 可以进一步更改状态,不会触发额外的重新渲染
  • 可以获取更新前的DOM状态

示例

export default {
  data() {
    return {
      count: 0,
      lastCount: 0
    }
  },
  methods: {
    increment() {
      this.count++;
    }
  },
  beforeUpdate() {
    console.log('beforeUpdate钩子执行了');
    // 记录更新前的DOM中显示的值
    const domValue = parseInt(document.getElementById('counter').textContent);
    console.log('DOM中的值:', domValue);
    console.log('data中的值:', this.count);
    
    // 记录上一次的值
    this.lastCount = domValue;
  }
}

适用场景

  • 在DOM更新前获取当前滚动位置等DOM状态
  • 手动移除已添加的事件监听器
  • 更新前的状态保存
  • 根据新数据决定是否需要取消更新操作

updated

由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。

特点

  • 组件DOM已经更新完成
  • 可以执行依赖于更新后DOM的操作
  • 应避免在此钩子中修改状态,可能导致无限循环
  • 如果需要相应状态改变,应该使用计算属性或watcher

示例

export default {
  data() {
    return {
      items: [],
      isLoading: false
    }
  },
  methods: {
    async loadMoreItems() {
      this.isLoading = true;
      const response = await fetch('https://api.example.com/items');
      const newItems = await response.json();
      this.items = [...this.items, ...newItems];
      this.isLoading = false;
    }
  },
  updated() {
    console.log('updated钩子执行了');
    
    // 如果新内容被加载,滚动到底部
    if (this.items.length && !this.isLoading) {
      const container = this.$refs.itemsContainer;
      if (container) {
        // 滚动到新加载的内容
        container.scrollTop = container.scrollHeight;
      }
    }
    
    // 注意:避免在此处修改会触发更新的数据
    // 错误示范: this.items = [...]; // 会导致无限循环!
  }
}

适用场景

  • 执行依赖于更新后DOM的计算(如动态调整高度)
  • 第三方库的DOM更新同步
  • 滚动位置的调整
  • 更新后的表单状态处理

销毁阶段钩子

beforeUnmount (Vue 3) / beforeDestroy (Vue 2)

在卸载组件实例之前调用。在这个阶段,实例仍然完全可用。

特点

  • 组件实例仍然完全可用
  • DOM元素仍然存在
  • 常用于清理工作,如清除定时器、取消网络请求等

示例

export default {
  data() {
    return {
      intervalId: null,
      fetchController: null
    }
  },
  created() {
    // 设置定时更新
    this.intervalId = setInterval(() => {
      console.log('定时更新');
      this.updateData();
    }, 3000);
    
    // 设置可取消的网络请求
    this.fetchController = new AbortController();
  },
  methods: {
    async updateData() {
      try {
        const response = await fetch('https://api.example.com/data', {
          signal: this.fetchController.signal
        });
        const data = await response.json();
        this.processData(data);
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error('数据更新失败:', error);
        }
      }
    },
    processData(data) {
      // 处理获取的数据
    }
  },
  beforeUnmount() { // Vue 3 
  // beforeDestroy() { // Vue 2
    console.log('beforeUnmount钩子执行了');
    
    // 清除定时器
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
    
    // 取消进行中的网络请求
    if (this.fetchController) {
      this.fetchController.abort();
      this.fetchController = null;
    }
    
    // 移除所有可能的事件监听器
    window.removeEventListener('resize', this.handleResize);
  }
}

适用场景

  • 清除定时器和计时器
  • 取消网络请求
  • 移除事件监听器
  • 取消订阅外部消息源
  • 销毁可能造成内存泄漏的引用

unmounted (Vue 3) / destroyed (Vue 2)

卸载组件实例后调用。调用此钩子时,组件实例的所有指令已被解绑,所有事件监听器已被移除。

特点

  • 组件实例已被完全销毁
  • 所有子组件也已被销毁
  • 不应该再访问DOM元素和组件实例

示例

export default {
  unmounted() { // Vue 3
  // destroyed() { // Vue 2
    console.log('unmounted钩子执行了');
    console.log('组件已完全销毁');
    
    // 可以通知父组件或其他系统该组件已销毁
    this.$emit('component-unmounted', this.componentId);
    
    // 可以执行一些额外的清理
    localStorage.removeItem(`cache_${this.componentId}`);
  }
}

适用场景

  • 组件销毁后的日志记录
  • 通知系统其他部分组件已销毁
  • 清理本地存储或会话存储中的相关数据
  • 分析组件生命周期数据

特殊钩子

activated 和 deactivated

这两个钩子函数只在使用了 <keep-alive> 组件包裹的动态组件中可用。

activated:被 keep-alive 缓存的组件激活时调用。
deactivated:被 keep-alive 缓存的组件停用时调用。

示例

export default {
  data() {
    return {
      loadTime: null,
      timeSinceActivation: 0,
      timer: null
    }
  },
  activated() {
    console.log('activated钩子执行了');
    // 记录组件被激活的时间
    this.loadTime = new Date();
    
    // 开始计时,记录组件被激活后的停留时间
    this.timer = setInterval(() => {
      this.timeSinceActivation = Math.floor(
        (new Date() - this.loadTime) / 1000
      );
    }, 1000);
    
    // 组件激活时重新获取最新数据
    this.fetchLatestData();
  },
  deactivated() {
    console.log('deactivated钩子执行了');
    // 记录用户在此组件停留的总时间
    const stayTime = Math.floor((new Date() - this.loadTime) / 1000);
    console.log(`用户在组件停留了 ${stayTime}`);
    
    // 清除计时器
    clearInterval(this.timer);
    
    // 可以保存一些状态,以便下次激活时恢复
    localStorage.setItem('scrollPosition', window.scrollY);
  },
  methods: {
    fetchLatestData() {
      // 获取最新数据的逻辑
    }
  }
}

适用场景

  • 需要根据组件的可见性执行逻辑的场景
  • 页面浏览统计和分析
  • 表单状态的保存和恢复
  • 数据的懒加载和刷新
  • 动画和过渡效果控制

errorCaptured

当捕获一个来自子孙组件的错误时被调用。

特点

  • 接收三个参数:错误对象、发生错误的组件实例和错误来源信息
  • 可以返回 false 阻止错误继续向上传播
  • 用于优雅处理组件树中的错误

示例

export default {
  errorCaptured(error, instance, info) {
    console.log('errorCaptured钩子捕获到错误');
    console.error('错误信息:', error);
    console.log('错误组件实例:', instance);
    console.log('错误来源信息:', info);
    
    // 记录错误
    this.logError(error, info);
    
    // 显示用户友好的错误信息
    this.showErrorNotification('抱歉,出现了一个错误,我们正在处理');
    
    // 返回false阻止错误继续向上传播
    return false;
  },
  methods: {
    logError(error, info) {
      // 将错误信息发送到服务器日志系统
    },
    showErrorNotification(message) {
      // 显示用户友好的错误消息
      this.errorMessage = message;
      this.showErrorModal = true;
    }
  }
}

适用场景

  • 构建错误边界来捕获子组件错误
  • 防止因组件错误导致整个应用崩溃
  • 实现应用级错误日志和监控
  • 为用户提供友好的错误提示
  • 尝试从错误中恢复应用状态

renderTracked 和 renderTriggered (Vue 3 特有)

这两个钩子用于调试。它们仅在开发模式下生效,仅用于开发阶段。

renderTracked:跟踪虚拟DOM重新渲染时触发。接收包含触发渲染的依赖的信息。
renderTriggered:当虚拟DOM重新渲染被触发时调用。接收包含触发重新渲染的依赖的信息。

示例

export default {
  renderTracked(event) {
    console.log('renderTracked钩子执行了');
    console.log('跟踪的渲染依赖:', event);
  },
  renderTriggered(event) {
    console.log('renderTriggered钩子执行了');
    console.log('触发重新渲染的依赖:', event);
    console.log(`${event.target.__proto__.constructor.name}.${event.key} 触发`);
  }
}

适用场景

  • 分析组件渲染性能
  • 调试过度渲染问题
  • 识别渲染触发源
  • 优化数据变化和DOM更新

Vue 2与Vue 3生命周期钩子对比

Vue 3 中一些生命周期钩子名称发生了变化,同时也提供了Composition API的等效钩子函数。

Vue 2 选项式APIVue 3 选项式APIVue 3 Composition API
beforeCreatebeforeCreatesetup()
createdcreatedsetup()
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroybeforeUnmountonBeforeUnmount
destroyedunmountedonUnmounted
activatedactivatedonActivated
deactivateddeactivatedonDeactivated
errorCapturederrorCapturedonErrorCaptured
-renderTrackedonRenderTracked
-renderTriggeredonRenderTriggered
-serverPrefetchonServerPrefetch

选项式API vs Composition API示例

// 选项式API (Vue 2 和 Vue 3)
export default {
  data() {
    return {
      message: 'Hello'
    }
  },
  mounted() {
    console.log('组件已挂载');
    console.log(this.message);
  },
  updated() {
    console.log('组件已更新');
  },
  beforeUnmount() {
    console.log('组件即将卸载');
  }
}

// Composition API (Vue 3)
import { ref, onMounted, onUpdated, onBeforeUnmount } from 'vue';

export default {
  setup() {
    const message = ref('Hello');
    
    onMounted(() => {
      console.log('组件已挂载');
      console.log(message.value);
    });
    
    onUpdated(() => {
      console.log('组件已更新');
    });
    
    onBeforeUnmount(() => {
      console.log('组件即将卸载');
    });
    
    return {
      message
    }
  }
}

最佳实践与常见问题

生命周期钩子最佳实践

  1. 在正确的钩子中执行操作

    • 数据获取:created
    • DOM操作:mounted
    • 清理工作:beforeUnmount
  2. 避免在不必要的钩子中执行昂贵操作

    • 避免在经常触发的 updated 钩子中执行复杂计算
    • 优先使用计算属性和侦听器替代 updated 钩子中的逻辑
  3. 注意钩子中的异步操作

    • 确保组件销毁时取消未完成的异步操作
    • 使用 this.$nextTick()await nextTick() 等待DOM更新完成
  4. 组件间通信

    • 在父组件的 mounted 调用对子组件的操作
    • 使用 $refs 访问子组件实例

常见问题与解决方案

  1. 钩子执行顺序问题

问题:父子组件的生命周期钩子执行顺序可能令人困惑。
解决:了解执行顺序:父组件beforeCreate→父created→父beforeMount→子beforeCreate→子created→子beforeMount→子mounted→父mounted

父 beforeCreate
父 created
父 beforeMount
  子 beforeCreate
  子 created
  子 beforeMount
  子 mounted
父 mounted
  1. 在更新钩子中修改数据导致无限循环

问题:在 updated 钩子中再次修改数据会触发新的更新周期,导致无限循环。
解决:在 updated 中添加条件检查,或使用计算属性和侦听器代替。

// 错误示例
updated() {
  this.count++; // 会导致无限循环!
}

// 正确示例
updated() {
  if (!this.hasUpdated) {
    this.hasUpdated = true;
    this.finalizeUpdate();
  }
}
  1. DOM还未渲染就尝试操作

问题:在 created 中尝试访问DOM元素报错。
解决:将DOM操作移到 mounted 钩子中,或使用 $nextTick

created() {
  // 错误: document.getElementById('myElement') 可能为 null
  
  // 正确: 使用 $nextTick
  this.$nextTick(() => {
    // DOM 现在已更新
    const element = document.getElementById('myElement');
  });
}
  1. 组件销毁后仍然更新数据

问题:异步操作完成后组件已销毁,但仍尝试更新数据导致警告。
解决:跟踪组件是否已销毁,或在 beforeUnmount 中取消异步操作。

export default {
  data() {
    return {
      isDestroyed: false,
      fetchController: new AbortController()
    }
  },
  methods: {
    async fetchData() {
      try {
        const response = await fetch('/api/data', {
          signal: this.fetchController.signal
        });
        const data = await response.json();
        
        // 检查组件是否已销毁
        if (!this.isDestroyed) {
          this.data = data;
        }
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error(error);
        }
      }
    }
  },
  beforeUnmount() {
    this.isDestroyed = true;
    this.fetchController.abort();
  }
}

综合案例

下面是一个用户资料编辑组件的综合案例,展示了不同生命周期钩子的使用:

export default {
  name: 'UserProfileEditor',
  props: {
    userId: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      user: null,
      originalUserData: null,
      isLoading: true,
      isSaving: false,
      error: null,
      saveTimer: null,
      formChanged: false,
      unsavedChanges: false,
      imageUploader: null
    }
  },
  // 创建阶段:准备数据
  beforeCreate() {
    console.log('1. beforeCreate - 组件初始化');
  },
  created() {
    console.log('2. created - 加载用户数据');
    // 获取用户数据
    this.fetchUserData();
    
    // 添加页面离开提示
    window.addEventListener('beforeunload', this.handlePageLeave);
  },
  // 挂载阶段:操作DOM
  beforeMount() {
    console.log('3. beforeMount - 准备渲染DOM');
  },
  mounted() {
    console.log('4. mounted - DOM已渲染,初始化编辑器');
    
    // 初始化第三方图片上传组件
    this.initImageUploader();
    
    // 设置自动保存定时器
    this.saveTimer = setInterval(() => {
      if (this.formChanged && !this.isSaving) {
        this.autoSave();
        this.formChanged = false;
      }
    }, 30000); // 每30秒自动保存一次
  },
  // 更新阶段:响应数据变化
  beforeUpdate() {
    console.log('5. beforeUpdate - 数据已更新,DOM即将重新渲染');
  },
  updated() {
    console.log('6. updated - DOM已重新渲染');
    
    // 如果表单数据与原始数据不同,标记为已更改
    if (this.user && this.originalUserData) {
      const currentData = JSON.stringify(this.user);
      const originalData = JSON.stringify(this.originalUserData);
      
      if (currentData !== originalData) {
        this.unsavedChanges = true;
        this.formChanged = true;
      } else {
        this.unsavedChanges = false;
      }
    }
  },
  // 销毁阶段:清理资源
  beforeUnmount() {
    console.log('7. beforeUnmount - 组件即将销毁,清理资源');
    
    // 提示保存未保存的更改
    if (this.unsavedChanges) {
      this.saveChanges();
    }
    
    // 清除定时器
    clearInterval(this.saveTimer);
    
    // 销毁图片上传组件
    if (this.imageUploader) {
      this.imageUploader.destroy();
    }
    
    // 移除事件监听器
    window.removeEventListener('beforeunload', this.handlePageLeave);
  },
  unmounted() {
    console.log('8. unmounted - 组件已销毁');
  },
  // 特殊钩子:错误捕获
  errorCaptured(error, vm, info) {
    console.error('错误捕获:', error, info);
    this.error = `发生错误: ${error.message}`;
    
    // 记录错误
    this.logError(error, info);
    
    // 防止错误向上传播
    return false;
  },
  methods: {
    async fetchUserData() {
      try {
        this.isLoading = true;
        this.error = null;
        
        const response = await fetch(`/api/users/${this.userId}`);
        if (!response.ok) throw new Error('获取用户数据失败');
        
        this.user = await response.json();
        // 保存原始数据副本用于比较
        this.originalUserData = JSON.parse(JSON.stringify(this.user));
      } catch (error) {
        this.error = error.message;
        console.error('获取用户数据错误:', error);
      } finally {
        this.isLoading = false;
      }
    },
    initImageUploader() {
      const uploadElement = this.$refs.imageUploader;
      if (!uploadElement) return;
      
      // 初始化假设的图片上传库
      this.imageUploader = new ImageUploader(uploadElement, {
        maxSize: 5 * 1024 * 1024, // 5MB
        onUpload: this.handleImageUpload
      });
    },
    async saveChanges() {
      if (!this.user) return;
      
      try {
        this.isSaving = true;
        
        const response = await fetch(`/api/users/${this.userId}`, {
          method: 'PUT',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(this.user)
        });
        
        if (!response.ok) throw new Error('保存数据失败');
        
        // 更新原始数据
        this.originalUserData = JSON.parse(JSON.stringify(this.user));
        this.unsavedChanges = false;
        
        // 显示成功提示
        this.showMessage('保存成功');
      } catch (error) {
        this.error = error.message;
        console.error('保存用户数据错误:', error);
        this.showMessage('保存失败: ' + error.message, 'error');
      } finally {
        this.isSaving = false;
      }
    },
    autoSave() {
      console.log('执行自动保存...');
      this.saveChanges();
    },
    handleImageUpload(result) {
      if (result.success) {
        this.user.avatarUrl = result.url;
      } else {
        this.error = '图片上传失败: ' + result.error;
      }
    },
    handlePageLeave(event) {
      if (this.unsavedChanges) {
        const message = '有未保存的更改,确定要离开吗?';
        event.returnValue = message;
        return message;
      }
    },
    logError(error, info) {
      // 发送错误到日志服务器
      fetch('/api/log-error', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          error: error.message,
          stack: error.stack,
          info,
          component: 'UserProfileEditor',
          userId: this.userId,
          timestamp: new Date().toISOString()
        })
      }).catch(e => console.error('无法记录错误:', e));
    },
    showMessage(text, type = 'success') {
      // 显示消息提示
      console.log(`[${type}] ${text}`);
      // 实际应用中可能使用UI组件库的消息提示功能
    }
  }
}

总结

Vue的生命周期钩子提供了完善的机制,允许开发者在组件不同阶段执行代码,从而实现各种复杂的功能和优化。

关键要点回顾

  1. 生命周期阶段

    • 创建阶段:beforeCreatecreated
    • 挂载阶段:beforeMountmounted
    • 更新阶段:beforeUpdateupdated
    • 销毁阶段:beforeUnmountunmounted
    • 特殊钩子:activateddeactivatederrorCaptured
  2. 常见使用场景

    • 数据初始化和API调用:created
    • DOM操作和第三方库初始化:mounted
    • 数据变化后的DOM更新:updated
    • 资源清理:beforeUnmount
  3. Vue 2与Vue 3的区别

    • Vue 3重命名了部分生命周期钩子
    • Vue 3新增了Composition API形式的生命周期钩子
  4. 最佳实践

    • 在正确的钩子中执行正确的操作
    • 避免不必要的性能消耗
    • 确保正确清理资源
    • 理解父子组件生命周期钩子的执行顺序

深入理解Vue的生命周期钩子,将帮助你更有效地组织代码逻辑,提高应用性能,并构建更加健壮的Vue应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈凯哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值