跳到主要内容

script setup 与宏能力

Vue 3 时代,单文件组件最常见的写法已经不是传统的 export default {},而是 <script setup>

它的价值不只是“代码更短”,而是把模板、响应式状态、组件输入输出和类型推断放进了一个更自然的结构里。

为什么 <script setup> 会成为主流

传统写法的问题,不在于不能用,而在于组件一复杂,逻辑会散。

  • props 在一处
  • methods 在一处
  • computed 在一处
  • watch 在一处
  • 生命周期钩子在另一处

<script setup> 让相关逻辑可以靠得更近。一个表单、一段异步请求、一个弹窗交互,可以在同一块代码里完成状态定义、派生、监听和输出。

最常见的几个宏

defineProps

定义组件输入。

<script setup lang="ts">
const props = defineProps<{
id: string
disabled?: boolean
}>()
</script>

3.5 之后,如果需要解构 props,也有更自然的响应式写法。

<script setup lang="ts">
const { disabled = false } = defineProps<{
disabled?: boolean
}>()
</script>

defineEmits

定义组件发出的事件。

<script setup lang="ts">
const emit = defineEmits<{
submit: [id: string]
cancel: []
}>()
</script>

这比“组件内部随手 emit('xxx')”更稳,尤其适合多人协作和 TS 项目。

defineExpose

控制组件对外暴露什么。

<script setup lang="ts">
import { ref } from 'vue'

const visible = ref(false)

function open() {
visible.value = true
}

defineExpose({ open })
</script>

适合弹窗、表单、图表容器这类需要让父组件直接调用方法的场景。

defineSlots

给插槽补类型信息。

<script setup lang="ts">
defineSlots<{
default(props: { active: boolean }): any
footer(): any
}>()
</script>

这是 3.3 之后很值得补的一块。组件库、业务容器组件里尤其有用。

defineOptions

<script setup> 里声明组件选项。

<script setup lang="ts">
defineOptions({
name: 'UserCard',
inheritAttrs: false,
})
</script>

这让 <script setup> 不需要再为了一个 nameinheritAttrs 回退到双脚本结构。

defineModel

3.4 稳定后,这个宏就进入了“可以放心用”的范围。

<script setup lang="ts">
const model = defineModel<string>({ required: true })
</script>

<template>
<input v-model="model" />
</template>

适合把“组件对外双向绑定”写得更统一。表单组件、输入组件、筛选面板会很常见。

<script setup> 的几个现实问题

1. 不是所有逻辑都该堆在一个文件里

<script setup> 很方便,但也容易把组件写成“什么都塞进去”。

状态定义、派生值、监听、副作用、接口请求、埋点、权限判断全堆在一起时,短代码也会变成难读代码。真正稳定的写法,还是要把可复用逻辑拆到 composables。

2. props 解构不是所有版本都一样

早期 Vue 3 对 defineProps() 解构的限制很强,很多文档都会提醒“不要直接解构,否则丢响应式”。

这条经验在 3.5 之后要更新。现在响应式解构已经成为正式能力,但老项目、老文章、老代码习惯还会保留旧说法,阅读时需要分版本判断。

3. 宏不是运行时 API

definePropsdefineEmitsdefineModel 这些都属于编译时宏,不是普通函数。

这一点会影响两个判断:

  • 不能像普通函数那样任意挪位置
  • 阅读源码和排查构建问题时,要把它们当成“编译器约定”来理解

哪些能力最值得优先掌握

如果只抓最常用的一批,建议先掌握这些:

  • defineProps
  • defineEmits
  • defineExpose
  • defineModel
  • defineOptions
  • props 响应式解构

defineSlots 更偏组件库和复杂容器组件,但也很值得了解。

一句话判断

Vue 3 现在已经不是“Composition API 能不能用”的阶段,而是“<script setup> 和宏能力已经足够成熟,可以把很多组件写法收得更干净”的阶段。