一目拾贝
- 缘起:一个真实的开发困扰
- 背景:Vue 3 的两种组件写法
- 核心问题:为什么想要"双脚本"?
- 技术现状:不同构建工具的差异
- 解决方案:因地制宜的选择
- 最佳实践:推荐的工作流
- 小结与总结
缘起:一个真实的开发困扰
最近在 Vue 3 项目中遇到一个有趣的问题:想要在同一个 .vue
文件中同时使用 <script setup>
的简洁语法和普通 <script>
的组件选项,就像这样:
js
<script setup>
// 响应式数据、方法等逻辑
const count = ref(0)
const increment = () => count.value++
</script>
<script>
export default {
name: 'MyComponent',
components: {
CustomButton: () => import('./CustomButton.vue')
}
}
</script>
这个想法听起来很美好,但现实却给了我们当头一棒。
背景:Vue 3 的两种组件写法
Vue 3 为我们提供了两种组件编写方式:
选项式 API(Options API) :
js
<script>
export default {
name: 'MyComponent',
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
</script>
组合式 API + <script setup>
:
js
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
核心问题:为什么想要"双脚本"?
开发者们想要"双脚本"的原因其实很实际:
- 组件命名需求 :
<script setup>
默认无法设置组件名,而组件名在调试、DevTools 中很重要 - 组件注册:某些场景下需要手动注册子组件,如别名 或 变量命名组件
js
import { Select, SelectOption, PageHeader, Tag, Button } from 'ant-design-vue'
...
components: {
// 别名
'a-select': Select,
'a-select-option': SelectOption,
// 变量命名组件
[PageHeader.name]: PageHeader,
[Tag.name]: Tag,
[Button.name]: Button
}
- 渐进式迁移:从选项式 API 迁移到组合式 API 时的过渡需求
- 团队协作:不同开发者习惯不同写法
技术现状:不同构建工具的差异
这里有个关键问题:你的构建工具决定了能否实现"双脚本" 。
Vite 项目:有解决方案
如果你用的是 Vite,恭喜你!有一个专门的插件:vite-plugin-vue-setup-extend
arduino
npm install vite-plugin-vue-setup-extend --save-dev
在 vite.config.ts
中配置:
js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
plugins: [
vue(),
vueSetupExtend()
]
})
然后你就可以愉快地写"双脚本"了:
js
<script setup>
const count = ref(0)
</script>
<script>
export default {
name: 'MyComponent'
}
</script>
Vue CLI 项目:无解
如果你用的是 Vue CLI(基于 Webpack),很遗憾😭,目前没有官方或社区插件支持这种写法。
Vue CLI 项目只能二选一:
- 要么用
<script setup>
- 要么用普通
<script>
解决方案:因地制宜的选择
方案一:升级到 Vue 3.3+ 使用 defineOptions
如果你的 Vue 版本是 3.3 及以上,可以使用 defineOptions
:
js
<script setup>
defineOptions({
name: 'MyComponent',
components: {
CustomButton: () => import('./CustomButton.vue')
}
})
const count = ref(0)
</script>
方案二:迁移到 Vite
如果项目允许,考虑从 Vue CLI 迁移到 Vite:
- 安装 Vite 相关依赖
- 创建
vite.config.ts
- 配置
vite-plugin-vue-setup-extend
- 享受"双脚本"的便利
方案三:统一使用一种写法
最稳妥的方案是统一团队代码风格:
推荐:纯 <script setup>
js
<script setup>
// 组件名通过文件名或目录结构体现
// 子组件直接 import 使用,无需注册
import CustomButton from './CustomButton.vue'
const count = ref(0)
</script>
最佳实践:推荐的工作流
基于实际项目经验,我推荐这样的工作流:
- 新项目 :直接使用 Vite +
<script setup>
+defineOptions
- 老项目 :逐步迁移到
<script setup>
,统一代码风格 - 团队规范:制定明确的组件编写规范,避免混用
小结
要点梳理:
- Vue 3 的"双脚本"需求源于实际开发中的命名和注册需求
- Vite 项目可以通过
vite-plugin-vue-setup-extend
实现 - Vue CLI 项目目前无法实现,需要选择单一写法
- Vue 3.3+ 的
defineOptions
提供了官方解决方案 - 统一代码风格比追求"双脚本"更重要
总结
Vue 3 的"双脚本"需求反映了开发者对灵活性的追求,但技术实现受限于构建工具。与其纠结于语法糖的混用,不如专注于代码的可维护性和团队协作效率。
在实际项目中,统一的代码风格和清晰的组件结构往往比语法糖的便利性更重要。选择适合你项目的方案,保持代码的一致性,这才是真正的最佳实践。
记住:技术是为了解决问题,而不是制造问题。选择简单有效的方案,往往比追求复杂的"完美"解决方案更实用。