setup 函数 和 setup 语法糖

很多同学在学 Vue3 的时候会发现,有两种写法:

  • 一种是传统的 setup 函数
  • 一种是更简洁的 <script setup> 语法糖

看起来功能都差不多,到底有没有区别呢? 今天咱们就用大白话给大家解释清楚。


一、两个写法长啥样?

1. setup 函数写法

js 复制代码
<template>
  <div>
    <h1>{{ msg }}</h1>
    <button @click="increase">count: {{ count }}</button>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  name: 'FooSetupFn',
  setup(props, { expose }) {
    const msg = 'Hello from setup()'
    const count = ref(0)
    function increase() {
      count.value++
    }

    // 如果需要控制暴露出去的内容
    expose({ msg, count, increase })

    // setup 函数需要手动 return
    return {
      msg,
      count,
      increase,
    }
  }
}
</script>

2. <script setup> 语法糖写法

js 复制代码
<template>
  <div>
    <h1>{{ msg }}</h1>
    <button @click="increase">count: {{ count }}</button>
  </div>
</template>

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

const msg = 'Hello from <script setup>'
const count = ref(0)

function increase() {
  count.value++
}

// 如果要控制暴露,可以用 defineExpose
defineExpose({
  msg,
  count,
  increase
})
</script>

二、运行效果有区别吗?

运行效果其实完全一样:页面都会显示一个标题和一个按钮,点按钮数字会加 1。

所以很多人就会觉得: 这不就是两个写法吗?功能完全一样啊!

但实际上,它们在 底层编译结果默认暴露行为 上是有区别的。


三、内部编译结果区别

Vue 单文件组件(.vue 文件)是不能直接被浏览器运行的,它要经过 编译

我们用 vite-plugin-inspect 插件看编译结果,就能发现区别。

多了expose():


1. setup 函数的编译结果

setup 函数的内容,原封不动放到组件配置对象里:

js 复制代码
const _sfc_main = {
  name: "FooSetupFn",
  setup(props, { expose }) {
    const msg = "Hello from setup()"
    const count = ref(0)
    function increase() {
      count.value++
    }

    expose() // 控制暴露
    return { msg, count, increase }
  }
}

它返回的东西(msg, count, increase),都会被挂到模板里用。


2. <script setup> 的编译结果

<script setup> 会被编译成一个 setup 函数,但是 Vue 会帮你自动 return 里面的变量:

js 复制代码
const _sfc_main = {
  name: "FooScriptSetup",
  setup(__props, { expose }) {
    const msg = "Hello from <script setup>"
    const count = ref(0)
    function increase() {
      count.value++
    }

    // 注意!Vue 自动帮你调用了 expose()
    expose()

    return { msg, count, increase, ref } // 所有顶层变量都会暴露
  }
}

区别就在于:

  • 普通 setup 函数:你自己决定 return 什么。
  • <script setup>:你定义的变量默认都会暴露给模板用。

四、为啥 <script setup> 打印 ref 结果是空的?

当我们用 ref 获取子组件实例,然后打印时:

  • setup 函数组件:实例对象里会看到 msg、count、increase。
  • <script setup> 组件:实例对象是空的,看不到 msg、count、increase。

为啥?

因为 <script setup> 里,Vue 默认加了一行:

js 复制代码
expose()

啥意思呢?意思就是:我不暴露任何东西。 所以你在父组件里拿到子组件实例时,看不到 msg、count 等等。


五、那我想暴露怎么办?

Vue 给我们提供了两个方法:

1. 在 setup 函数里用 expose

js 复制代码
setup(props, { expose }) {
  const msg = 'Hello'
  const count = ref(0)

  expose({ msg, count }) // 只暴露 msg 和 count

  return { msg, count }
}

2. 在 <script setup> 里用 defineExpose

vue 复制代码
<script setup>
import { ref } from 'vue'

const msg = 'Hello'
const count = ref(0)
function increase() {
  count.value++
}

// 只暴露这三个
defineExpose({
  msg,
  count,
  increase
})
</script>

这里的 defineExpose 是一个 宏函数 (编译时才存在),不需要 import,它最后会被编译成 expose()


六、总结

  • <script setup> 就是 setup 函数的语法糖,写法更简洁。

  • setup 函数 → 你自己决定 return 什么。

  • <script setup> → 默认所有变量都能用,但对子组件实例默认不暴露。

  • 想控制暴露的内容:

    • setup 里用 expose()
    • <script setup> 里用 defineExpose()

一句话总结: 👉 平时写组件用 <script setup>,简单省事。 👉 真要做库或者控制暴露,就用 expose / defineExpose

相关推荐
泉城老铁3 小时前
Spring Boot和Vue.js项目中实现文件压缩下载功能
前端·spring boot·后端
我是天龙_绍3 小时前
vue3 中,setup 函数 和 <script setup> 的区别
前端
krifyFan3 小时前
vue3+elementPlus el-date-picker 自定义禁用状态hook 实现结束时间不能小于开始时间
前端·vue.js·elementui
卷Java3 小时前
WXML 编译错误修复总结
xml·java·前端·微信小程序·uni-app·webview
SevgiliD3 小时前
解决使用 fixed固定列时el-table导致纵向滚动条问题
前端·vue.js·elementui
天蓝色的鱼鱼3 小时前
🚀 告别 Electron 的臃肿:用 Tauri 打造「轻如鸿毛」的桌面应用
前端
余大侠在劈柴3 小时前
go语言学习记录9.23
开发语言·前端·学习·golang·go
bitbitDown3 小时前
忍了一年多,我终于对i18n下手了
前端·javascript·架构
JarvanMo3 小时前
我尝试了Appwrite, Supabase和 Firebase Databases
前端·后端