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 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端