news 2026/3/12 3:58:26

Vue 3 中编写单文件组件(SFC)的编译时语法糖:<script setup>

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue 3 中编写单文件组件(SFC)的编译时语法糖:<script setup>

Vue3的<script setup>语法糖简化了Composition API的使用,主要特点包括:

  • 自动暴露顶级变量给模板
  • 组件自动注册
  • 使用defineProps/defineEmits声明属性和事件
  • 通过defineExpose暴露方法

它显著减少了样板代码,支持TypeScript类型推断和顶层await,使组件开发更简洁高效。


相比传统Options API,<script setup>代码量减少约30%,更适合现代JavaScript开发模式,是Vue3项目的推荐写法,尤其适合需要良好类型支持和追求开发效率的场景。


<script setup>


<script setup>Vue 3 中编写单文件组件(SFC)的编译时语法糖,它让 Composition API 的代码更加简洁、直观。


这是 Vue 3 最重要的开发体验改进之一。


基本语法

vue

<!-- 传统 Options API --> <script> export default { data() { return { count: 0 } }, methods: { increment() { this.count++ } } } </script> <!-- 使用 <script setup> --> <script setup> import { ref } from 'vue' const count = ref(0) const increment = () => { count.value++ } </script> <template> <button @click="increment">{{ count }}</button> </template>

可以看到,代码量显著减少,更符合 JavaScript 的自然写法。


核心特性

1.顶级变量自动暴露给模板

<script setup>中声明的所有顶级变量(包括导入的)都会自动暴露给模板,无需return

vue

<script setup> import { ref } from 'vue' import MyComponent from './MyComponent.vue' // 自动暴露给模板 const count = ref(0) const message = 'Hello Vue 3!' const doubleCount = computed(() => count.value * 2) function increment() { count.value++ } </script> <template> <!-- 所有顶级变量都可以直接使用 --> <MyComponent /> <h1>{{ message }}</h1> <p>{{ count }} x 2 = {{ doubleCount }}</p> <button @click="increment">+1</button> </template>

2.组件自动注册

导入的组件无需在components选项中注册,可以直接在模板中使用。

vue

<script setup> // 导入后直接可用 import Button from './Button.vue' import Modal from './Modal.vue' import Icon from './Icon.vue' </script> <template> <Button>点击</Button> <Modal /> <Icon name="user" /> </template>

3.定义 Props 和 Emits

使用definePropsdefineEmits编译器宏来声明:

vue

<script setup> // 定义 Props const props = defineProps({ title: { type: String, required: true }, count: { type: Number, default: 0 } }) // 定义 Emits(两种方式) // 方式1:数组形式 const emit = defineEmits(['update:title', 'submit']) // 方式2:对象形式(可添加验证) const emit = defineEmits({ 'update:title': (value) => { return typeof value === 'string' }, 'submit': null // 无需验证 }) // 触发事件 const updateTitle = () => { emit('update:title', '新标题') } </script> <template> <h1>{{ title }}</h1> <p>计数: {{ count }}</p> </template>

4.使用defineExpose暴露组件方法

默认情况下,<script setup>中的变量是私有的。如果需要父组件访问,需要使用defineExpose

<!-- Child.vue --> <script setup> import { ref } from 'vue' const count = ref(0) const reset = () => { count.value = 0 } // 只暴露 reset 方法,count 保持私有 defineExpose({ reset }) </script> <!-- Parent.vue --> <script setup> import { ref, onMounted } from 'vue' import Child from './Child.vue' const childRef = ref(null) onMounted(() => { // 只能访问暴露的方法 childRef.value?.reset() // ✅ 可以调用 console.log(childRef.value?.count) // ❌ undefined(私有) }) </script> <template> <Child ref="childRef" /> </template>

5.使用useSlotsuseAttrs

<script setup> import { useSlots, useAttrs } from 'vue' // 访问插槽 const slots = useSlots() // 访问非 props 的属性(class, style, 自定义属性等) const attrs = useAttrs() console.log(slots.default) // 默认插槽内容 console.log(attrs.class) // 传递的 class </script>

高级用法

1.与 TypeScript 完美集成

<script setup lang="ts"> // 使用类型声明 Props 和 Emits interface Props { title: string count?: number } interface Emits { (e: 'update:title', value: string): void (e: 'submit'): void } // 带类型的 Props const props = withDefaults(defineProps<Props>(), { count: 0 }) // 带类型的 Emits const emit = defineEmits<Emits>() // 自动类型推断 const doubleCount = computed(() => (props.count || 0) * 2) </script>

2.顶层await

<script setup>支持顶层await,结果会自动编译成async setup()

vue

<script setup> // 直接使用 await,无需包装 const user = await fetchUser() const posts = await fetchPosts() // 甚至可以在模板中使用 const data = await fetchData() </script> <template> <div v-if="data"> {{ data }} </div> </template>

3.动态组件

vue

<script setup> import { shallowRef } from 'vue' import Home from './Home.vue' import About from './About.vue' import Contact from './Contact.vue' const components = { Home, About, Contact } const currentTab = shallowRef('Home') const currentComponent = computed(() => components[currentTab.value]) </script> <template> <button v-for="tab in Object.keys(components)" :key="tab" @click="currentTab = tab" > {{ tab }} </button> <component :is="currentComponent" /> </template>

4.组合式函数的使用

<script setup> import { useMouse, useLocalStorage } from './composables' // 直接使用组合式函数 const { x, y } = useMouse() const { value: theme } = useLocalStorage('theme', 'light') // 组合多个功能 const { data, loading, error, fetchData } = useFetch('/api/data') </script>

与传统<script>的对比

特性<script setup>传统<script>
代码量更简洁,减少 ~30%需要更多的样板代码
组件注册自动注册,无需components选项需要在components中注册
暴露变量自动暴露顶级变量需要从setup()中返回
Props/Emits使用defineProps/defineEmits编译器宏使用propsemits选项
TypeScript更好的类型推断和集成类型支持有限
顶层 await支持不支持
学习曲线对 React Hooks 用户更友好对 Vue 2 用户更熟悉

常见问题和解决方案

问题1:需要访问组件实例?

vue

<script setup> import { getCurrentInstance } from 'vue' // 获取当前组件实例(谨慎使用) const instance = getCurrentInstance() // 访问全局属性 console.log(instance.appContext.config.globalProperties.$router) // 尽量使用 Composition API 替代 // 例如使用 useRouter() 而不是 this.$router </script>

问题2:与 Options API 混用?

vue

<!-- 可以同时使用,但不推荐 --> <script> export default { inheritAttrs: false } </script> <script setup> // Composition API 代码 </script>

问题3:Props 的响应式解构

vue

<script setup> import { toRefs } from 'vue' const props = defineProps({ user: Object, active: Boolean }) // ❌ 错误:直接解构会丢失响应式 const { user, active } = props // ✅ 正确:使用 toRefs 保持响应式 const { user, active } = toRefs(props) // 或者使用 computed const userName = computed(() => props.user?.name) </script>

最佳实践

1.统一使用<script setup>

在新项目中,默认使用<script setup>,保持代码风格统一。

2.合理组织代码顺序

<script setup> // 1. 导入依赖 import { ref, computed } from 'vue' import { useRouter } from 'vue-router' // 2. 组件导入 import Button from './Button.vue' import Modal from './Modal.vue' // 3. Props/Emits 定义 const props = defineProps(/* ... */) const emit = defineEmits(/* ... */) // 4. 组合式函数调用 const router = useRouter() const { data, fetch } = useFetch() // 5. 响应式状态 const count = ref(0) const form = reactive({/* ... */}) // 6. 计算属性 const doubleCount = computed(() => count.value * 2) // 7. 方法函数 const handleSubmit = async () => { // ... } // 8. 生命周期/侦听器 onMounted(() => { fetch() }) // 9. 暴露给父组件的方法 defineExpose({ submit: handleSubmit }) </script>

3.为复杂组件使用组合式函数

当组件逻辑复杂时,将其拆分为组合式函数:

<script setup> // 将复杂逻辑抽离 import { useUserManagement } from './composables/useUserManagement' import { useFormValidation } from './composables/useFormValidation' const { users, loading, error, fetchUsers, deleteUser } = useUserManagement() const { form, errors, validate, resetForm } = useFormValidation() </script>

总结

<script setup>是 Vue 3 的重大改进,它:

主要优势:

  • 代码更简洁:减少样板代码,提高开发效率

  • 类型支持更好:与 TypeScript 完美集成

  • 自动暴露:无需手动返回模板使用的变量

  • 组件自动注册:导入即用

  • 更符合现代 JS 习惯:像写普通 JavaScript 一样写 Vue


需要注意:

  • 学习新的 API:definePropsdefineEmitsdefineExpose

  • 需要了解响应式保持(使用toRefs

  • 部分 Options API 概念需要转换思维


适用场景:

  • 所有新的 Vue 3 项目

  • 使用 Composition API 的组件

  • 需要良好 TypeScript 支持的项目

  • 希望减少样板代码,提高开发效率


<script setup>代表了 Vue 组件编写的未来方向,是 Vue 3 开发的首选方式。虽然一开始需要适应新的语法,但一旦习惯,你会发现自己再也回不去传统的写法了!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/8 22:04:22

永磁同步电机Matlab/Simulink仿真模型探索

永磁同步电机Matlab/Simulink仿真模型 矢量控制直接转矩控制滑膜无感高频注入扩展卡尔曼模型参考自适应开环控制VFIF弱磁mpta模糊控制在电机控制领域&#xff0c;永磁同步电机&#xff08;PMSM&#xff09;凭借其高效、高功率密度等优点&#xff0c;广泛应用于工业、交通等众多…

作者头像 李华
网站建设 2026/3/10 18:47:48

从Anaconda迁移到Miniconda-Python3.9的理由,你知道几个?

从Anaconda迁移到Miniconda-Python3.9的理由&#xff0c;你知道几个&#xff1f; 在数据科学与人工智能项目日益复杂的今天&#xff0c;一个常见的场景是&#xff1a;你刚接手同事的代码仓库&#xff0c;满怀信心地运行 pip install -r requirements.txt&#xff0c;结果却卡在…

作者头像 李华
网站建设 2026/3/4 1:08:56

有效修复 Google Photos 备份卡住问题

当 Google Photos 备份卡住时&#xff0c;备份过程会持续更长时间&#xff0c;非常耗时&#xff0c;尤其是在您正准备用手机玩游戏或看电影的时候。为了轻松解决此备份问题&#xff0c;我们列出了 14 种简单实用的解决方法。如果这些方法都无效&#xff0c;您仍然可以使用其他方…

作者头像 李华
网站建设 2026/3/4 6:20:12

自考人必看!9个降AI率工具推荐,高效避坑指南

自考人必看&#xff01;9个降AI率工具推荐&#xff0c;高效避坑指南 AI降重工具&#xff1a;自考人的高效避坑指南 随着人工智能技术的快速发展&#xff0c;越来越多的自考生在论文写作过程中依赖AI生成内容。然而&#xff0c;AI生成的文章往往存在明显的“AI痕迹”&#xff0c…

作者头像 李华
网站建设 2026/3/7 9:25:18

基于单片机温湿度检测显示报警控制系统设计

一、系统整体设计方案 本系统以 STC89C52RC 单片机为控制核心&#xff0c;聚焦工业仓储、家庭室内、实验室等场景的温湿度监测需求&#xff0c;可实现环境温湿度实时采集、数据直观显示、超阈值声光报警及参数阈值自定义功能&#xff0c;兼顾检测精度与报警及时性&#xff0c;为…

作者头像 李华