Vue 3 组件开发中的"双脚本"困境

一目拾贝

  1. 缘起:一个真实的开发困扰
  2. 背景:Vue 3 的两种组件写法
  3. 核心问题:为什么想要"双脚本"?
  4. 技术现状:不同构建工具的差异
  5. 解决方案:因地制宜的选择
  6. 最佳实践:推荐的工作流
  7. 小结与总结

缘起:一个真实的开发困扰

最近在 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>

核心问题:为什么想要"双脚本"?

开发者们想要"双脚本"的原因其实很实际:

  1. 组件命名需求<script setup> 默认无法设置组件名,而组件名在调试、DevTools 中很重要
  2. 组件注册:某些场景下需要手动注册子组件,如别名 或 变量命名组件
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
  }
  1. 渐进式迁移:从选项式 API 迁移到组合式 API 时的过渡需求
  2. 团队协作:不同开发者习惯不同写法

技术现状:不同构建工具的差异

这里有个关键问题:你的构建工具决定了能否实现"双脚本"

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:

  1. 安装 Vite 相关依赖
  2. 创建 vite.config.ts
  3. 配置 vite-plugin-vue-setup-extend
  4. 享受"双脚本"的便利

方案三:统一使用一种写法

最稳妥的方案是统一团队代码风格:

推荐:纯 <script setup>

js 复制代码
<script setup>
// 组件名通过文件名或目录结构体现
// 子组件直接 import 使用,无需注册
import CustomButton from './CustomButton.vue'
const count = ref(0)
</script>

最佳实践:推荐的工作流

基于实际项目经验,我推荐这样的工作流:

  1. 新项目 :直接使用 Vite + <script setup> + defineOptions
  2. 老项目 :逐步迁移到 <script setup>,统一代码风格
  3. 团队规范:制定明确的组件编写规范,避免混用

小结

要点梳理:

  • Vue 3 的"双脚本"需求源于实际开发中的命名和注册需求
  • Vite 项目可以通过 vite-plugin-vue-setup-extend 实现
  • Vue CLI 项目目前无法实现,需要选择单一写法
  • Vue 3.3+ 的 defineOptions 提供了官方解决方案
  • 统一代码风格比追求"双脚本"更重要

总结

Vue 3 的"双脚本"需求反映了开发者对灵活性的追求,但技术实现受限于构建工具。与其纠结于语法糖的混用,不如专注于代码的可维护性和团队协作效率。

在实际项目中,统一的代码风格和清晰的组件结构往往比语法糖的便利性更重要。选择适合你项目的方案,保持代码的一致性,这才是真正的最佳实践。

记住:技术是为了解决问题,而不是制造问题。选择简单有效的方案,往往比追求复杂的"完美"解决方案更实用。

相关推荐
码上暴富32 分钟前
axios请求的取消
前端·javascript·vue.js
JefferyXZF1 小时前
Next.js 初识:从 React 到全栈开发的第一步(一)
前端·全栈·next.js
一只韩非子2 小时前
AI时代,程序员如何优雅地搞定页面设计?
前端·ai编程
新中地GIS开发老师2 小时前
2025Mapbox零基础入门教程(14)定位功能
前端·javascript·arcgis·gis·mapbox·gis开发·地理信息科学
烛阴3 小时前
Int / Floor
前端·webgl
excel3 小时前
使用 PWA 时,为什么你必须手动添加更新逻辑,否则会报错?
前端
Moment3 小时前
Node.js 这么多后端框架,我到底该用哪个?🫠🫠🫠
前端·后端·node.js
尚学教辅学习资料3 小时前
SpringBoot3.x入门到精通系列: 2.3 Web开发基础
前端·springboot·web开发
han_3 小时前
前端遇到页面卡顿问题,如何排查和解决?
前端·javascript·性能优化