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> 不需要再为了一个 name 或 inheritAttrs 回退到双脚本结构。
defineModel
3.4 稳定后,这个宏就进入了“可以放心用”的范围。
<script setup lang="ts">
const model = defineModel<string>({ required: true })
</script>
<template>
<input v-model="model" />
</template>
适合把“组件对外双向绑定”写得更统一。表单组件、输入组件、筛选面板会很常见。