人人都会AI编程

setup 函数与 <script setup> 语法糖

更新时间:2026-07-09

在 Vue 3 的组合式 API 中,setup 是组件逻辑的入口,而 <script setup> 是它的语法糖封装。理解这两者的关系,是掌握组合式 API 的关键一步。

setup 函数:组合式 API 的入口

在组件的选项式写法中,数据、方法、计算属性等分散在 datamethodscomputed 等不同选项中。而 setup 函数将它们聚合在一起,所有组合式 API 都必须在 setup 内部调用。

<script>
import { ref, onMounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    function increment() {
      count.value++
    }
    onMounted(() => {
      console.log('组件已挂载')
    })

    // 必须显式返回,模板才能使用
    return {
      count,
      increment
    }
  }
}
</script>

setup 函数的执行时机在 beforeCreatecreated 之前,此时组件实例尚未完全创建,所以无法通过 this 访问组件实例。这反而让逻辑更纯粹——你面对的就是普通的 JavaScript 变量和函数,this 的困扰不复存在。

注意:所有需要在模板中使用的数据或方法,都必须通过 return 暴露出去。随着组件逻辑增长,return 语句会变得越来越冗长,这也是 <script setup> 出现的原因之一。

<script setup>:让组合式 API 更简洁

<script setup> 是 Vue 3.2 引入的编译时语法糖,它在单文件组件(SFC)中使用。它的核心变化是:你不再需要手动 return,顶层变量和导入会直接向模板暴露

<script setup>
import { ref, onMounted } from 'vue'

const count = ref(0)
function increment() {
  count.value++
}
onMounted(() => {
  console.log('组件已挂载')
})
</script>

无需 export default,无需 setup() 函数,无需 return。模板中可以直接使用 countincrement。这种写法让组件逻辑更接近普通的 JavaScript 模块,代码量明显减少。

两者的核心差异

| 特性 | setup() 函数 | <script setup> |
|------|----------------|------------------|
| 模板访问变量 | 必须显式 return | 顶层变量自动暴露 |
| 导入组件 | 需要在 components 选项注册 | 导入即注册,无需显式声明 |
| 使用 propsemits | 通过 setup(props, { emit }) 接收 | 使用 definePropsdefineEmits 宏 |
| TypeScript 支持 | 需要手动标注类型 | 原生支持更流畅 |
| 代码简洁度 | 样板代码较多 | 极简,适合大逻辑量组件 |

definePropsdefineEmits 的用法

<script setup> 中,propsemits 的声明使用了编译器宏,不需要显式导入,它们是编译时的语法糖。

<script setup>
// 声明 props,返回值可直接使用
const props = defineProps({
  title: String,
  count: { type: Number, default: 0 }
})
// or with TS types
// const props = defineProps<{ title: string; count?: number }>()

// 声明 emits
const emit = defineEmits(['update:title', 'submit'])

function handleChange() {
  emit('update:title', '新标题')
}
</script>

这些宏只在 <script setup> 中有效,编译时会被正确转换,不会增加运行时开销。

实际选型建议

  • 新项目统一使用 <script setup>:它更简洁,TypeScript 支持更好,也是官方推荐的未来方向。
  • 需要选项式功能的场景用 setup() 函数:例如某些老项目迁移,或者需要混用选项式 API(比如仍要使用 inheritAttrs 等),可以继续使用明确的 setup() 函数。
  • 逻辑复用时提炼自定义 Hooks:无论是 setup() 还是 <script setup>,都可以将可复用的逻辑抽离到独立的组合式函数(以 useXxx 命名)中,只需导入调用即可,这才是组合式 API 最强大的能力。
// useCounter.js
import { ref } from 'vue'
export function useCounter() {
  const count = ref(0)
  function increment() { count.value++ }
  return { count, increment }
}

然后在组件中直接使用:

<script setup>
import { useCounter } from './useCounter'
const { count, increment } = useCounter()
</script>

简单来说,setup() 是基础,<script setup> 是进化——它用更少的代码实现了同样甚至更灵活的功能,让你专注于逻辑本身,而不是框架的规则。