一、故事开始:我以为我不懂 Vue,后来发现是我太懂了
某天下午,团队在重构一个 Vue3 项目,我在 Review 同事 PR 时,眼前一亮:
<script setup>
defineExpose({
'@vue:mounted': () => {
console.log('组件被挂载了!')
}
})
</script>
我当场懵住:@vue:mounted?Vue3 官方文档里根本没见过这个写法啊!
Google、Vue 官网、GitHub issues 都翻遍了,愣是没找到解释。
是我脱离社区太久了吗?还是我同事在用什么黑科技?
——于是,我开始了这场“破案之旅”。
二、真相浮出水面:这不是你熟悉的 mounted
我们熟悉的 Vue 生命周期,在 <script setup> 中通常这样写:
onMounted(() => {
console.log('组件挂载完毕')
})
那 @vue:mounted 是什么?
答案是:这是一种 DevTools 用的调试钩子,不是正式 API。
重点来了:它是 Vue DevTools 和调试工具注入的一种 内置调试 hook,用于追踪生命周期或组件状态,而不是供开发者主动调用的 API。
三、它从哪儿来的?这才是真正的幕后黑手
这个写法的根源来自 Vue 插件的调试 API(如 devtools hook、宏指令 transform) 。通常以下几种场景可能看到它:
- 插件作者通过
defineExpose暴露内部方法供 DevTools 追踪 - 在一些低层框架(如 Vite 插件、unplugin 系列)中注入调试钩子
- Vue SFC Playground 或 Nuxt Devtools 中也会生成类似结构
你可以理解为:
@vue:* 是 Vue DevTools 为了能在组件树中更好地追踪生命周期和行为而设置的“隐秘通道”。
四、能用在项目中吗?不建议!除非你是 DevTools 作者
这段代码虽然不会报错,但不建议业务代码中使用,原因有三:
- 不是文档公开 API,未来版本可能随时变动或废弃
- 不是为开发者使用设计的,而是为调试工具准备的
- 会增加阅读成本,影响代码清晰性
更标准的写法应为:
import { onMounted } from 'vue'
onMounted(() => {
console.log('组件加载完成')
})
五、那 defineExpose 到底该怎么用?
defineExpose 是 <script setup> 的语法糖,用于将内部逻辑暴露给外部使用(比如父组件 ref 调用)。
例如:
<script setup>
function scrollToBottom() {
// ...
}
defineExpose({ scrollToBottom })
</script>
外部组件可通过 ref 使用:
<MyComponent ref="compRef" />
compRef.value.scrollToBottom()
⚠️ 所以 @vue:mounted 并不是官方推荐的 expose 内容,只是调试时内部使用的注入项。
六、尾声:魔法的尽头,是理解底层
这件小事提醒了我:
当你看到一些“非主流”的代码写法,先别急着 Google,先从源码、插件、调试工具入手,可能能发现意想不到的内幕。
“@vue:mounted”不是错,它只是不是给你用的。
希望这篇文章,能帮你和你的同事少走点弯路,也能激发你对 Vue 生态更深层的探索欲望。
📎附录:相关延伸阅读
- Vue3 生命周期官方文档
- [Vue DevTools 调试原理解析(进阶) - 敬请期待下一篇!]