想搞懂Vue2组件从出生到消失的全过程?开发时处理数据加载、DOM操作、性能优化,全得吃透生命周期!这篇把Vue2生命周期拆成问题逐个讲,从阶段划分到实际开发咋用,一次性理清楚~
Vue2生命周期有哪些阶段?各自负责啥事儿?
Vue2里,组件从创建、渲染、更新到销毁的整个流程,被拆成创建、挂载、更新、销毁四大阶段,每个阶段对应「钩子函数」,能让咱在特定时机写逻辑。先看创建阶段:
beforeCreate
:组件实例刚初始化,data、methods都没挂上!这时候连this.data
都拿不到,基本用不上。created
:数据观测、事件配置全搞定了!能访问data里的变量、调用methods里的方法,也能发异步请求(比如调接口拿数据),因为此时this
能拿到响应式数据,请求回来直接赋值,页面会自动更新~
然后是挂载阶段:把虚拟DOM变成真实DOM,挂到页面上。
beforeMount
:模板刚编译成虚拟DOM,还没生成真实DOM!想操作页面元素?门儿都没有~mounted
:真实DOM终于挂载完成!这时候能操作DOM(比如用document.getElementById
拿节点,或者初始化echarts这类第三方库),也能拿到子组件的实例~
接着是更新阶段:当组件里的数据变化时触发(比如data里的变量被修改)。
beforeUpdate
:数据已经变了,但DOM还没更新!能拿到“旧DOM”,适合在DOM更新前做临时处理。updated
:DOM已经跟着数据更新完了!这时候可以根据新DOM做操作(比如重新计算列表高度)。
销毁阶段:组件从页面上移除,实例被销毁。
beforeDestroy
:组件销毁前的“最后挣扎”!还能访问组件实例,得赶紧清理资源(比如清定时器、解绑自定义事件)。destroyed
:组件彻底销毁,实例和所有子组件都解绑了,想操作也没机会咯~
开发时咋选对应的生命周期钩子?举个例子
不同场景选不同钩子,效率和 Bug 都会少很多!场景1:初始化数据+发异步请求 → 选created
比如做「用户信息卡片」组件,需要调接口拿用户头像、昵称,在created
里发请求特合适:此时this.data
已经能响应式更新,请求回来把数据赋值给data里的变量,页面自动渲染~要是放mounted
里,虽然也能发请求,但多等了DOM挂载的时间,没必要~
场景2:操作真实DOM/初始化第三方库 → 选mounted
比如用echarts做图表,得先有个DOM容器(比如<div id="chart"></div>
)。mounted
时真实DOM已经存在,才能通过document.getElementById('chart')
拿到容器,初始化echarts实例~要是放beforeMount
,DOM都没生成,肯定找不到节点!
场景3:数据更新后做操作 → 选updated
比如做「可编辑表格」,数据变化后要自动调整列宽。updated
里DOM已经更新完,这时候计算列宽才准确~要是放beforeUpdate
,DOM还是旧的,计算出来的结果肯定不对。
场景4:清理资源(定时器、事件监听) → 选beforeDestroy
比如组件里有个定时器,每隔1秒刷新数据,要是不清理,组件销毁后定时器还在跑,会导致内存泄漏(页面关了还占内存)!所以得在beforeDestroy
里用clearInterval(timer)
把定时器清掉~
父子组件的生命周期执行顺序是啥?开发时要注意啥?
父子组件的生命周期不是同时执行的,而是“父等子”的逻辑——父组件得等子组件完成对应阶段,自己才继续。以加载阶段(创建+挂载)为例,执行顺序是:
父beforeCreate
→ 父created
→ 父beforeMount
→ 子beforeCreate
→ 子created
→ 子beforeMount
→ 子mounted
→ 父mounted
所以父组件的mounted
执行时,所有子组件都已经完成挂载!要是父组件想操作子组件的DOM,得等子组件的mounted
跑完才行~
更新阶段的顺序是:
父beforeUpdate
→ 子beforeUpdate
→ 子updated
→ 父updated
因为父数据变化可能触发子组件更新,所以子组件得先完成更新,父组件再更新自己的DOM~
销毁阶段的顺序是:
父beforeDestroy
→ 子beforeDestroy
→ 子destroyed
→ 父destroyed
父组件销毁时,会先触发自己的beforeDestroy
,再逐个销毁子组件,确保子组件的资源(比如定时器)都清理干净~
举个实际开发的坑:父组件给子组件传props,子组件在created
里处理props,要是父组件在自己的mounted
里直接操作子组件的DOM,得确认子组件已经mounted
,否则可能拿到空节点!
Vue2和Vue3生命周期有啥不一样?对开发有影响不?
Vue3用「组合式API」后,生命周期写法变了,但阶段逻辑没咋变~Vue2是「选项式API」,直接写beforeCreate
、mounted
这些钩子;
Vue3在setup
里,得用onBeforeMount
、onMounted
这类函数(注意:Vue3里没有beforeCreate
和created
,因为setup
执行时机就在这两个钩子之间,所以初始化逻辑直接放setup
里就行)。
虽然写法不同,但阶段的作用时机是对应的:比如Vue3的onMounted
和Vue2的mounted
,都是真实DOM挂载后执行,要是项目从Vue2迁到Vue3,只要把钩子换成组合式API的写法,逻辑思路还是通的~
这些生命周期误区,你踩过吗?
开发时稍不注意,就容易掉坑里,看看你中过没~误区1:“beforeMount里能操作DOM?”
不行!beforeMount
时,模板刚变成虚拟DOM,真实DOM还没生成呢~想给某个div加class?根本找不到元素!得等mounted
之后才行。
误区2:“created里能拿到ref的DOM?”
也不行!ref
是依赖真实DOM存在的,created
时DOM还没开始挂载,所以this.$refs.xxx
肯定是undefined
~得放mounted
里拿。
误区3:“组件销毁后,定时器自动没了?”
想太多!Vue不会自动清理定时器,得自己在beforeDestroy
里手动清,比如做轮播图组件,要是没清定时器,组件销毁后定时器还在跑,切换页面后可能突然触发,导致报错~
实战:用生命周期优化组件性能
光懂理论不够,结合案例才知道咋用~案例1:实时刷新的新闻列表
created
:发第一次请求,获取初始新闻数据。mounted
:启动定时器(setInterval
),每隔5分钟请求新数据。beforeDestroy
:清除定时器(clearInterval(timer)
),避免内存泄漏。
案例2:可关闭的模态框
模态框需要“点击外部关闭”功能,得给document加点击事件:
mounted
:给document绑定click
事件,判断点击位置是否在模态框外,是的话关闭。beforeDestroy
:移除document的click
事件监听(document.removeEventListener
),否则多次打开模态框后,事件会叠加,点一次触发多次关闭逻辑!
吃透Vue2生命周期,开发时才能精准控制组件的“一生”——啥时候拿数据、啥时候操作DOM、啥时候清理资源,心里门儿清~下次写组件,别再纠结该把逻辑塞哪个钩子啦,对照场景选就对咯~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。