news 2026/4/16 21:34:00

Vue生命周期总结(四个阶段,八个钩子函数)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue生命周期总结(四个阶段,八个钩子函数)

目录

  • 一、Vue的生命周期阶段
  • 二、生命周期钩子函数
    • 1、创建阶段
      • 1、beforeCreate
      • 2、created (常用)
    • 2、挂载阶段
      • 1、beforeMount
      • 2、 mounted
    • 3、更新阶段
      • 1、beforeUpdate
      • 2、updated
    • 4、销毁阶段
      • 1、beforeDestroy
      • 2、destroyed

一、Vue的生命周期阶段

vue生命周期分为四个阶段
第一阶段(创建阶段):beforeCreate,created
第二阶段(挂载阶段):beforeMount(render),mounted
第三阶段(更新阶段):beforeUpdate,updated
第四阶段(销毁阶段):beforeDestroy,destroyed

二、生命周期钩子函数

1、创建阶段

1、beforeCreate

在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用。
作用核心:初始化Vue实例的响应式系统

beforeCreate(){// 此时Vue实例的响应式系统还未建立}

作用:
初始化事件系统和生命周期
数据观测 (data observation) 还未开始
计算属性 (computed) 和方法 (methods) 还未定义
应用场景:

exportdefault{beforeCreate(){// ⭐ 场景1:记录性能时间点this.$options.startTime=performance.now();// ⭐ 场景2:初始化非响应式数据this.staticConfig={version:'1.0.0',apiBaseUrl:process.env.API_URL};// ⭐ 场景3:预加载资源(如图片、字体)constpreloadImages=['/images/loading.gif','/images/error.png'];preloadImages.forEach(src=>{constimg=newImage();img.src=src;});// ❌ 不能做的事情:// console.log(this.message); // undefined// this.fetchData(); // undefined}}

2、created (常用)

在实例创建完成后被立即同步调用。在这一步中,实例已完成对选项的处理,意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。然而,挂载阶段还没开始,且 $el property 目前尚不可用。
解释:在这个阶段,可以访问到数据了,但是页面当中真实dom节点还是没有渲染出来,在这个钩子函数里面,可以进行相关初始化事件的绑定、发送请求操作。

created(){// 此时响应式系统已建立完成}

作用:
数据观测已完成
属性和方法已配置
计算属性已计算
DOM还未生成,$el属性不可用
应用场景:

exportdefault{data(){return{user:null,settings:{},productList:[]};},created(){// 场景1:发起异步数据请求(最常用)this.fetchInitialData();// 场景2:从本地存储读取数据this.loadFromLocalStorage();// 场景3:初始化组件状态this.initComponentState();// 场景4:设置事件总线监听this.setupEventBusListeners();// 场景5:初始化第三方服务配置this.initThirdPartyServices();},methods:{asyncfetchInitialData(){try{// 并行请求多个接口const[userRes,settingsRes,productsRes]=awaitPromise.all([axios.get('/api/user/profile'),axios.get('/api/user/settings'),axios.get('/api/products')]);this.user=userRes.data;this.settings=settingsRes.data;this.productList=productsRes.data;}catch(error){this.handleError(error);}},loadFromLocalStorage(){// 从本地存储恢复状态constsavedCart=localStorage.getItem('shoppingCart');if(savedCart){this.cartItems=JSON.parse(savedCart);}// 读取用户偏好consttheme=localStorage.getItem('theme')||'light';this.currentTheme=theme;},initComponentState(){// 根据URL参数初始化constquery=this.$route.query;if(query.category){this.activeCategory=query.category;}// 设置默认值this.pagination={page:1,pageSize:20,total:0};},setupEventBusListeners(){// 监听全局事件this.$eventBus.$on('user-logged-in',this.handleUserLogin);this.$eventBus.$on('notification',this.showNotification);},initThirdPartyServices(){// 初始化分析工具if(window.analytics){window.analytics.identify(this.userId);}// 初始化错误监控if(window.Sentry){window.Sentry.configureScope(scope=>{scope.setUser({id:this.userId});});}}}}

核心要点:
可以访问所有响应式数据
适合数据初始化工作
不能操作DOM
请求数据的最佳时机(减少白屏时间

2、挂载阶段

1、beforeMount

作用核心:将模板编译并挂载到真实DOM
在挂载开始之前被调用:相关的 render 函数首次被调用。
解释:代表dom马上就要被渲染出来了,但是却还没有真正的渲染出来,这个钩子函数与created钩子函数用法基本一致,可以进行相关初始化事件的绑定、发送ajax操作。

2、 mounted

挂载阶段的最后一个钩子函数,数据挂载完毕,真实dom元素也已经渲染完成了,这个钩子函数内部可以做一些实例化相关的操作

mounted(){// DOM已挂载完成,可以操作DOM}

作用:
虚拟DOM已挂载到真实DOM
$el属性可用
组件已完全渲染
应用场景:

exportdefault{mounted(){// 场景1:操作DOM元素(最常见)this.initDOMOperations();// 场景2:初始化第三方库(需要DOM)this.initThirdPartyLibraries();// 场景3:添加事件监听器this.bindEventListeners();// 场景4:执行依赖DOM的异步操作this.performDOMDependentAsyncTasks();// 场景5:测量DOM元素尺寸this.measureDOMElements();},methods:{initDOMOperations(){// 1. 聚焦输入框if(this.$refs.searchInput){this.$refs.searchInput.focus();this.$refs.searchInput.select();}// 2. 设置滚动位置constsavedScroll=sessionStorage.getItem('scrollPosition');if(savedScroll&&this.$refs.scrollContainer){this.$refs.scrollContainer.scrollTop=parseInt(savedScroll);}// 3. 动态修改样式this.$el.classList.add('loaded');this.$refs.header.style.backgroundColor=this.themeColor;},initThirdPartyLibraries(){// 1. 初始化图表库(ECharts/Chart.js)if(this.$refs.chart){this.chartInstance=echarts.init(this.$refs.chart);this.chartInstance.setOption(this.chartOptions);}// 2. 初始化地图(百度地图/高德地图)if(this.$refs.mapContainer){this.map=newAMap.Map(this.$refs.mapContainer,{zoom:12,center:[116.397428,39.90923]});}// 3. 初始化富文本编辑器if(this.$refs.editor){this.editor=newEditor({el:this.$refs.editor,content:this.content});}// 4. 初始化代码编辑器if(this.$refs.codeEditor){this.codeMirror=CodeMirror.fromTextArea(this.$refs.codeEditor,{mode:'javascript',theme:'material',lineNumbers:true});}},bindEventListeners(){// 1. 窗口大小变化监听window.addEventListener('resize',this.handleResize);// 2. 全局键盘事件document.addEventListener('keydown',this.handleGlobalKeydown);// 3. 滚动事件监听window.addEventListener('scroll',this.handleScroll,{passive:true});// 4. 鼠标事件this.$el.addEventListener('mouseenter',this.handleMouseEnter);this.$el.addEventListener('mouseleave',this.handleMouseLeave);},performDOMDependentAsyncTasks(){// 1. 延迟加载图片this.$nextTick(()=>{constlazyImages=this.$el.querySelectorAll('img[data-src]');lazyImages.forEach(img=>{img.src=img.dataset.src;});});// 2. 执行动画setTimeout(()=>{this.$el.classList.add('animate-in');},100);},measureDOMElements(){// 1. 获取元素尺寸if(this.$refs.container){constrect=this.$refs.container.getBoundingClientRect();this.containerWidth=rect.width;this.containerHeight=rect.height;}// 2. 计算响应式布局this.calculateResponsiveLayout();}},beforeDestroy(){// 🧹 必须清理!!!// 1. 移除事件监听window.removeEventListener('resize',this.handleResize);document.removeEventListener('keydown',this.handleGlobalKeydown);// 2. 销毁第三方库实例if(this.chartInstance){this.chartInstance.dispose();}if(this.map){this.map.destroy();}if(this.editor){this.editor.destroy();}// 3. 清理定时器clearTimeout(this.animationTimer);}}

3、更新阶段

1、beforeUpdate

在数据发生改变后,DOM 被更新之前被调用。这里适合在现有 DOM 将要被更新之前访问它,比如移除手动添加的事件监听器。
解释:这个钩子函数初始化的不会执行,当组件挂载完毕的时候,并且当数据改变的时候,才会立马执行,这个钩子函数获取dom的内容是更新之前的内容

beforeUpdate(){// 数据已变化,DOM更新前}

作用:
检测到数据变化
重新计算虚拟DOM
但还未更新真实DOM
应用场景:

exportdefault{data(){return{messages:[],scrollPosition:0};},beforeUpdate(){// ⭐ 场景1:保存DOM状态(如滚动位置)if(this.$refs.messageList){this.scrollPosition=this.$refs.messageList.scrollTop;this.scrollHeight=this.$refs.messageList.scrollHeight;}// ⭐ 场景2:检查数据变化类型if(this.messages.length!==this.previousMessageCount){this.hasNewMessages=true;}this.previousMessageCount=this.messages.length;// ⭐ 场景3:性能监控if(this.$options.performanceLogging){console.time('dom-update');}// ⭐ 场景4:取消不必要的操作if(this.isScrolling){console.log('正在滚动,延迟DOM更新');}// ❌ 不要在这里修改正在更新的数据// this.messages.push('新消息'); // 会导致无限循环}}

2、updated

在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。

updated(){// DOM已更新完成}

作用:
虚拟DOM的差异已应用到真实DOM
DOM更新完成
组件重新渲染完成

应用场景:

exportdefault{updated(){// ⭐ 场景1:恢复DOM状态(如滚动位置)if(this.$refs.messageList&&this.hasNewMessages){// 保持滚动在底部(聊天应用场景)this.$refs.messageList.scrollTop=this.$refs.messageList.scrollHeight;this.hasNewMessages=false;}// ⭐ 场景2:更新第三方库if(this.chartInstance&&this.chartDataChanged){this.chartInstance.setOption({series:[{data:this.chartData}]});this.chartDataChanged=false;}// ⭐ 场景3:执行DOM更新后的操作this.performPostUpdateOperations();// ⭐ 场景4:触发过渡动画if(this.shouldAnimate){this.$nextTick(()=>{this.$el.classList.add('update-complete');});}// ⭐ 场景5:性能日志if(this.$options.performanceLogging){console.timeEnd('dom-update');console.log(`DOM更新完成,耗时:${performance.now()-this.updateStartTime}ms`);}// ❌ 重要警告:避免在此修改响应式数据!// 错误示例:// if (this.count < 10) {// this.count++; // 会导致无限更新循环!// }// ✅ 正确做法:使用条件判断 + $nextTickif(this.shouldAutoIncrement&&this.count<this.maxCount){this.$nextTick(()=>{this.count++;});}},methods:{performPostUpdateOperations(){// 1. 高亮新增项constnewItems=this.$el.querySelectorAll('.item-new');newItems.forEach(item=>{item.classList.add('highlight');setTimeout(()=>{item.classList.remove('item-new');},1000);});// 2. 更新工具提示位置if(this.tooltips){this.tooltips.forEach(tooltip=>tooltip.updatePosition());}// 3. 触发自定义事件this.$emit('dom-updated',{timestamp:Date.now(),elementCount:this.$el.children.length});}}}

4、销毁阶段

作用核心:清理资源,防止内存泄漏

1、beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。
当组件销毁的时候,就会触发这个钩子函数代表销毁之前,可以做一些善后操作,可以清除一些初始化事件、定时器相关的东西。

beforeDestroy(){// Vue 2beforeUnmount(){// Vue 3// 实例销毁前,实例仍然完全可用}

作用:
实例即将销毁
所有功能仍然可用
最后的机会进行清理工作
应用场景:

exportdefault{data(){return{resources:{timers:[],listeners:[],connections:[]}};},beforeDestroy(){// 🧹 资源清理清单:// 1. 清理定时器this.resources.timers.forEach(timerId=>{clearInterval(timerId);clearTimeout(timerId);});// 2. 移除事件监听器this.resources.listeners.forEach(({target,event,handler})=>{target.removeEventListener(event,handler);});// 3. 关闭WebSocket/SSE连接if(this.websocket&&this.websocket.readyState===WebSocket.OPEN){this.websocket.close(1000,'组件销毁');}if(this.eventSource){this.eventSource.close();}// 4. 取消HTTP请求if(this.currentRequest){this.currentRequest.cancel('组件销毁,请求已取消');}// 5. 清理第三方库实例this.cleanupThirdPartyLibraries();// 6. 清理DOM引用this.$refs={};// 7. 移除全局状态引用this.removeGlobalReferences();// 8. 保存状态到本地存储this.saveStateToStorage();// 9. 发送销毁日志this.logDestruction();},methods:{cleanupThirdPartyLibraries(){// 清理各种第三方库constlibraries=['chartInstance','mapInstance','editorInstance','playerInstance','pdfViewer','codeMirror'];libraries.forEach(libName=>{if(this[libName]&&typeofthis[libName].destroy==='function'){this[libName].destroy();this[libName]=null;}});},removeGlobalReferences(){// 从全局对象中移除引用if(window.activeComponents){constindex=window.activeComponents.indexOf(this);if(index>-1){window.activeComponents.splice(index,1);}}// 清除全局事件处理器deletewindow[`${this._uid}_resize_handler`];},saveStateToStorage(){// 保存需要持久化的状态if(this.shouldPersistState){conststateToSave={formData:this.formData,filters:this.activeFilters,pagination:this.pagination};localStorage.setItem(`component_state_${this.componentId}`,JSON.stringify(stateToSave));}},logDestruction(){// 发送销毁统计navigator.sendBeacon('/api/component-lifecycle',JSON.stringify({component:this.$options.name,instanceId:this._uid,lifespan:Date.now()-this.createdAt,event:'beforeDestroy'}));}}}

2、destroyed

实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
Vue实例失去活性,完全丧失功能

destroyed(){// Vue 2unmounted(){// Vue 3// 实例已完全销毁}

作用:
实例已销毁
所有事件监听器已移除
所有子实例已销毁
所有指令已解绑

应用场景:

exportdefault{destroyed(){// ⭐ 场景1:最终清理确认console.assert(this.resources.timers.length===0,'还有未清理的定时器');console.assert(this.resources.listeners.length===0,'还有未清理的事件监听');// ⭐ 场景2:触发父组件回调this.$emit('component-destroyed',{instanceId:this._uid,name:this.$options.name});// ⭐ 场景3:更新应用级状态if(this.$root){this.$root.activeComponentCount--;}// ⭐ 场景4:性能分析记录if(window.performanceMonitor){window.performanceMonitor.recordComponentLifecycle(this.$options.name,'destroyed',performance.now()-this.createdAt);}// ❌ 此时不能访问实例数据// console.log(this.message); // undefined 或报错// ⭐ 场景5:内存泄漏检测辅助if(process.env.NODE_ENV==='development'){// 在开发环境帮助检测内存泄漏console.log(`组件${this.$options.name}已销毁,检查是否有内存泄漏`);}},created(){// 记录创建时间,用于计算生命周期时长this.createdAt=performance.now();}}
<template><div id="app"><p id="box">{{msg}}</p><button @click="change">更新</button></div></template><script>exportdefault{data(){return{msg:'hello'}},methods:{change(){this.msg='hello world'}},beforeCreate(){console.log('---------------->beforeCreate')console.log(this.msg,document.getElementById('box'))},created(){console.log('---------------->created')console.log(this.msg,document.getElementById('box'))},beforeMount(){console.log('---------------->beforeMount')console.log(this.msg,document.getElementById('box'))},mounted(){console.log('---------------->mounted')console.log(this.msg,document.getElementById('box'))},beforeUpdate(){console.log('---------------->beforeUpdate')console.log(this.$el.innerHTML)console.log(this.msg,document.getElementById('box'))},updated(){console.log('---------------->updated')console.log(this.$el.innerHTML)console.log(this.msg,document.getElementById('box'))}}</script>

当页面初始化挂载完成之后,

当数据改变之后又会触发beforeUpdate,updated两个钩子函数

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:15:45

Free-NTFS-for-Mac终极免费方案:苹果电脑完美读写NTFS磁盘完整指南

Free-NTFS-for-Mac终极免费方案&#xff1a;苹果电脑完美读写NTFS磁盘完整指南 【免费下载链接】Free-NTFS-for-Mac Nigate&#xff0c;一款支持苹果芯片的Free NTFS for Mac小工具软件。NTFS R/W for macOS. Support Intel/Apple Silicon now. 项目地址: https://gitcode.co…

作者头像 李华
网站建设 2026/4/16 14:29:17

最新版Java高频面试题(含答案)

一.java基础 1.八大基础类型 2.java三大特性 3.重载和重写的区别 4.pubilc、protected、(dafault)不写、private修饰符的作用范围 5.和equals的区别 6.hashcode()值相同&#xff0c;equals就一定为true 7.为什么重写equals()&#xff0c;就要重写hashcode()? 8.short …

作者头像 李华
网站建设 2026/4/16 12:21:18

Java 面试挂了 7 次后,我终于悟透了大厂面试官的「套路」

开头&#xff1a;3 年开发&#xff0c;面阿里被问懵的 3 个瞬间 "你说 HashMap 线程不安全&#xff0c;那 ConcurrentHashMap 在 JDK1.8 是怎么保证安全的&#xff1f;""Spring 事务传播机制里&#xff0c;REQUIRES_NEW 和 NESTED 有什么区别&#xff1f;举个实…

作者头像 李华
网站建设 2026/4/16 12:23:35

Android系统深度定制:从内核编译到功能模块开发的完整指南

Android系统深度定制&#xff1a;从内核编译到功能模块开发的完整指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable Android系统定制与ROM开发为技术爱好者提供了无限可能性。通过深入理…

作者头像 李华
网站建设 2026/4/16 12:15:32

飞书文档批量导出终极指南:25分钟搞定700+文档迁移

还在为飞书文档迁移发愁吗&#xff1f;每次手动下载文档都要花费数小时&#xff0c;还担心漏掉重要内容&#xff1f;作为经历过公司从飞书平台切换的过来人&#xff0c;我深知文档批量导出的痛点。今天分享的feishu-doc-export工具&#xff0c;让我从8小时的手动操作解放到25分…

作者头像 李华
网站建设 2026/4/16 16:10:22

终极批量歌词同步工具:LRCGET让离线音乐库焕发新生

终极批量歌词同步工具&#xff1a;LRCGET让离线音乐库焕发新生 【免费下载链接】lrcget Utility for mass-downloading LRC synced lyrics for your offline music library. 项目地址: https://gitcode.com/gh_mirrors/lr/lrcget 在数字音乐时代&#xff0c;拥有大量离线…

作者头像 李华