Vue3项目实战:从Vue2的mounted迁移到onMounted,我踩过的那些坑

馒猫子

Vue3实战迁移指南:从mounted到onMounted的避坑全记录

去年接手公司核心后台系统从Vue2到Vue3的迁移任务时,我本以为生命周期钩子的改动只是简单的重命名。直到在凌晨三点的办公室里,面对满屏的undefined错误,才意识到这个看似温和的API变更背后藏着多少"惊喜"。本文将分享我在300+组件迁移过程中总结出的实战经验,特别是mountedonMounted转换时那些官方文档没明说的细节。

1. 上下文丢失:this的消亡与替代方案

当第一次在onMounted里习惯性写下this.$el时,控制台的红色错误提示给了我最直接的Vue3欢迎仪式。Composition API最颠覆性的改变之一就是取消了组件实例的this绑定,这对mounted逻辑迁移的影响最为显著。

1.1 获取DOM元素的三种新方式

在Vue2中,我们通常这样访问DOM:

javascript复制mounted() {
  this.$el.style.backgroundColor = 'red'
  const button = this.$refs.submitButton
}

Vue3中对应的实现方式需要完全改变思维模式:

  1. 模板引用(推荐)
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>
  1. 获取根元素
javascript复制import { getCurrentInstance, onMounted } from 'vue'

onMounted(() => {
  const { proxy } = getCurrentInstance()
  console.log(proxy.$el) // 相当于Vue2的this.$el
})
  1. 原生DOM查询(不推荐但应急可用):
javascript复制onMounted(() => {
  document.querySelector('.app-container') // 慎用,破坏组件封装性
})

1.2 方法调用的正确姿势

Vue2中的常见模式:

javascript复制methods: {
  fetchData() {
    // ...
  },
  mounted() {
    this.fetchData()
  }
}

在Vue3中需要将方法显式暴露:

vue复制<script setup>
const fetchData = () => {
  // ...
}

onMounted(fetchData) // 直接传递函数引用
</script>

注意:如果方法中需要访问其他响应式变量,务必确保它们在同一个作用域内

2. 执行时机差异:那些意料之外的行为

在测试环境跑通所有用例后,我们自信满满地部署到预发布环境,却意外发现了大量渲染闪烁问题。深入排查才发现onMounted的执行时机与mounted存在微妙差异。

2.1 子组件挂载顺序的陷阱

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
})

2.2 `