news 2026/3/5 15:58:48

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/2 13:25:31

PyTorch安装踩坑总结:Windows/Linux/Mac通用解决方案

PyTorch安装避坑指南&#xff1a;跨平台环境配置的实战经验 在深度学习项目启动前&#xff0c;最让人头疼的往往不是模型设计或数据处理&#xff0c;而是那个看似简单的“第一步”——环境安装。你有没有遇到过这种情况&#xff1a;明明按照官方命令执行了 pip install torch&…

作者头像 李华
网站建设 2026/3/3 4:21:49

AppSpider 7.5.023 发布 - Web 应用程序安全测试

AppSpider 7.5.023 for Windows - Web 应用程序安全测试 Rapid7 Dynamic Application Security Testing (DAST) released December 2025 请访问原文链接&#xff1a;https://sysin.org/blog/appspider/ 查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff…

作者头像 李华
网站建设 2026/3/3 20:54:43

2025年技术领域大火!大模型应用开发工程师成为最火岗位,平均月薪高达30K+。2026年,抓住机遇入局,成为下一个技术界明星!

一、 市场现状&#xff1a;大模型应用开发工程师为何一将难求&#xff1f; 2025年&#xff0c;人工智能作为核心驱动力&#xff0c;正加速推动各行业智能化转型。根据摩根士丹利的研究&#xff0c;软件开发市场正以20%的年增长率扩张&#xff0c;预计到2029年将达到610亿美元。…

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

自由编辑+AI 赋能:ChatPPT与Nano Banana Pro的创作革命

一、什么是Nano Banana Pro&#xff1f;ChatPPT与Nano Banana Pro深度携手&#xff0c;AI美化PPT的体验彻底升级了。简单说&#xff0c;Nano Banana Pro是谷歌Gemini 3驱动的专业AI图像工具&#xff0c;能生成4K高清图像、支持精准编辑&#xff0c;还能融合参考图保持风格统一。…

作者头像 李华