去年接手公司核心后台系统从Vue2到Vue3的迁移任务时,我本以为生命周期钩子的改动只是简单的重命名。直到在凌晨三点的办公室里,面对满屏的undefined错误,才意识到这个看似温和的API变更背后藏着多少"惊喜"。本文将分享我在300+组件迁移过程中总结出的实战经验,特别是mounted到onMounted转换时那些官方文档没明说的细节。
当第一次在onMounted里习惯性写下this.$el时,控制台的红色错误提示给了我最直接的Vue3欢迎仪式。Composition API最颠覆性的改变之一就是取消了组件实例的this绑定,这对mounted逻辑迁移的影响最为显著。
在Vue2中,我们通常这样访问DOM:
javascript复制mounted() {
this.$el.style.backgroundColor = 'red'
const button = this.$refs.submitButton
}
Vue3中对应的实现方式需要完全改变思维模式:
vue复制<template>
<div ref="container">...</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const container = ref(null)
onMounted(() => {
container.value.style.border = '1px solid #eee'
})
</script>
javascript复制import { getCurrentInstance, onMounted } from 'vue'
onMounted(() => {
const { proxy } = getCurrentInstance()
console.log(proxy.$el) // 相当于Vue2的this.$el
})
javascript复制onMounted(() => {
document.querySelector('.app-container') // 慎用,破坏组件封装性
})
Vue2中的常见模式:
javascript复制methods: {
fetchData() {
// ...
},
mounted() {
this.fetchData()
}
}
在Vue3中需要将方法显式暴露:
vue复制<script setup>
const fetchData = () => {
// ...
}
onMounted(fetchData) // 直接传递函数引用
</script>
注意:如果方法中需要访问其他响应式变量,务必确保它们在同一个作用域内
在测试环境跑通所有用例后,我们自信满满地部署到预发布环境,却意外发现了大量渲染闪烁问题。深入排查才发现onMounted的执行时机与mounted存在微妙差异。
Vue2的生命周期顺序:
code复制父beforeMount → 父mounted → 子beforeMount → 子mounted
Vue3的Composition API顺序:
code复制父setup → 子setup → 父onMounted → 子onMounted
这个变化导致我们在父组件onMounted中操作子组件DOM的逻辑全部失效。解决方案是使用nextTick:
javascript复制import { nextTick } from 'vue'
onMounted(async () => {
await nextTick()
// 现在可以安全操作子组件DOM
})