vue3中使用 script setup 时关于变量定义的一些总结

news/2025/3/15 17:15:18/文章来源:https://www.cnblogs.com/smile-fanyin/p/18773928

前言:

在vue3中使用<script setup>,在定义变量的时候,有时候会用到比较多的ref,如:

const a = ref(false)
const b = ref(true)
const c = ref(null)

如果用传统的写法 setup() ,传统写法中所有的变量都是用 const state = reactive({//...})  生成的,最后通过 return {...toRefs(state)} 返回,如:

export default {name: 'LeftSideBar',setup() {const state = reactive({isCollapsed: false,showHistory: true,activeMenu: null,marketPositionStyle: {},knowledgePositionStyle: {},workenchPositionStyle: {},menuItems: [{ name: 'AI超市', iconName: "icon-AIShop" },{ name: '知识库', iconName: "icon-knowledgeBase" },]})}// 方法定义const fun1 = () => {//
    }// 返回所有需要暴露的内容return {//定义的变量
        ...toRefs(state),fun1,// 其他需要暴露的方法...
        }
}

如何在使用`<script setup>`时更高效地管理多个变量呢?

一、两种写法的本质区别

核心原则:无论是否使用 <script setup>,Vue3 的响应式原理是一致的,只是变量组织方式不同。

特性传统 setup() 写法<script setup> 写法
暴露方式 手动 return 自动暴露顶层变量
代码组织 需要包裹在 setup() 函数内 直接写在顶层作用域
变量定义灵活性 可以用 reactive 批量管理 推荐多用 ref,但也能用 reactive 优化

二、<script setup> 中更简洁的写法

方法 1:用 reactive + toRefs 批量管理变量

<script setup>
import { reactive, toRefs } from 'vue'// 将多个相关变量分组管理
const uiState = reactive({isCollapsed: false,showHistory: true,activeMenu: null,selectedHistory: null
})const guideState = reactive({isShowGuide: true,showMarketGuide: false,showKnowledgeGuide: false,showWorkenchGuide: true
})// 转换为 ref 集合(保持响应式)
const { isCollapsed, showHistory, activeMenu, selectedHistory } = toRefs(uiState)
const { isShowGuide, showMarketGuide, showKnowledgeGuide, showWorkenchGuide } = toRefs(guideState)
</script>

方法 2:使用对象解构(推荐)

<script setup>
import { reactive } from 'vue'// 使用单个 reactive 对象管理所有状态
const state = reactive({isCollapsed: false,showHistory: true,activeMenu: null,selectedHistory: null,isShowGuide: true,showMarketGuide: false,showKnowledgeGuide: false,showWorkenchGuide: true
})// 在模板中直接通过 state.xxx 访问
</script><template><div :class="{ collapsed: state.isCollapsed }">{{ state.showHistory }}</div>
</template>

三、两种写法的对比

传统 setup() 写法

export default {setup() {const state = reactive({isCollapsed: false,showHistory: true})return {...toRefs(state) // 必须手动返回
    }}
}

<script setup> 优化写法

<script setup>
import { reactive } from 'vue'// 定义
const state = reactive({isCollapsed: false,showHistory: true
})// 自动暴露 state 对象
</script><template><!-- 访问方式 --><div>{{ state.isCollapsed }}</div>
</template>

四、重要注意事项

  1. 响应式保持规则

    • 直接解构 reactive 对象会丢失响应式:

      // ❌ 错误!解构会丢失响应式
      const { isCollapsed } = reactive({ isCollapsed: false })
    • 必须使用 toRefs

      // ✅ 正确
      const state = reactive({ isCollapsed: false })
      const { isCollapsed } = toRefs(state)
  2. 模板访问差异

    <!-- 方法1:通过 state 对象访问 -->
    {{ state.isCollapsed }}<!-- 方法2:解构后直接访问 -->
    {{ isCollapsed }}
  3. 性能考量

    • 单个 reactive 对象比多个 ref 内存占用更小

    • 频繁访问嵌套属性时,state.xxxxxx.value 更易读

五、最佳实践建议

  1. 按功能模块分组

    // 用户界面状态
    const uiState = reactive({isCollapsed: false,showHistory: true
    })// 业务数据状态
    const dataState = reactive({items: [],loading: false
    })
  2. 组合式函数封装

    // useSidebar.js
    export default () => {const state = reactive({isCollapsed: false,showHistory: true})const toggle = () => {state.isCollapsed = !state.isCollapsed}return { ...toRefs(state), toggle }
    }
  3. 模板中的访问优化

    <script setup>
    const state = reactive({isCollapsed: false,showHistory: true
    })
    </script><template><!-- 直接访问 --><button @click="state.isCollapsed = !state.isCollapsed">{{ state.isCollapsed ? '展开' : '折叠' }}</button><!-- 或使用解构 --><button @click="isCollapsed = !isCollapsed">{{ isCollapsed ? '展开' : '折叠' }}</button>
    </template>

六、完整示例对比

原始多个 ref 写法

<script setup>
const isCollapsed = ref(false)
const showHistory = ref(true)
const activeMenu = ref(null)
// ...其他 10+ 个 ref
</script>

优化后的 reactive 写法

<script setup>
const uiState = reactive({isCollapsed: false,showHistory: true,activeMenu: null,selectedHistory: null,isShowGuide: true,showMarketGuide: false,showKnowledgeGuide: false,showWorkenchGuide: true
})const { isCollapsed, showHistory } = toRefs(uiState)
</script><template><div :class="{ collapsed: uiState.isCollapsed }">{{ uiState.showHistory }}</div>
</template>

总结

  1. <script setup> 中完全可以使用 reactive 来批量管理变量

  2. toRefs 是关键桥梁:将 reactive 对象转换为多个 ref

  3. 按需选择模式

    • 简单组件:直接用多个 ref

    • 复杂组件:用 reactive 分组管理

  4. 保持响应式:始终通过 .value 或 reactive 对象属性访问值

通过合理使用 reactive + toRefs 的组合,完全可以实现与传统 setup() 函数相似的简洁代码结构,同时享受 <script setup> 的自动暴露优势。

 

 

---------------------------   分割线(可忽略)------------------------------------

文章由deepseek生成,记录个人问题和seepseek思考过程。

个人问题:

我看用vue3 <script setup> 的话,在定义变量的时候,定义了一大堆,个人觉得有点麻烦,如下:
const isCollapsed = ref(false)
const showHistory = ref(true)
const activeMenu = ref(null)
const selectedHistory = ref(null)
const isShowGuide = ref(true)
const showMarketGuide = ref(false)
const showKnowledgeGuide = ref(false)
const showWorkenchGuide = ref(true)
在之前的没有用 <script setup> 语法糖的时候,用的是传统的写法  setup() ,传统写法中所有的变量都是用const state = reactive({//...}) 生成的,最后通过return {...toRefs(state)}返回要暴露的变量了。
我的疑问是:是不是使用了<script setup>语法糖的时候,定义基本类型的数据,就必须用ref定义?有多少个就定义多少个,是不是没有更简洁的写法?而用传统的写法  setup() 的时候,可以用reactive批量定义变量,最后只用通过return中的toRefs返回就行?

思考过程:

好的,用户现在对Vue3的两种写法(`<script setup>`和传统`setup()`函数)在定义变量时的差异感到困惑。他们注意到在使用`<script setup>`时,每个基本类型的变量都需要单独用`ref`定义,显得比较繁琐,而传统写法可以通过`reactive`批量定义并通过`toRefs`一次性暴露,想知道是否有更简洁的方式。首先,我需要确认用户的核心疑问:在使用`<script setup>`时,是否必须对每个基本类型变量使用`ref`,而无法像传统`setup()`那样用`reactive`批量管理。用户希望了解是否有更简洁的方法,同时想明确两种写法在变量管理上的优劣。接下来,我需要回忆Vue3的响应式系统。`reactive`用于对象,而`ref`适用于所有类型,包括基本类型。在传统`setup()`中,使用`reactive`包裹对象,然后通过`toRefs`解构,可以方便地批量暴露变量。但在`<script setup>`中,由于自动暴露顶层变量的特性,直接使用`reactive`会导致模板中需要访问对象的属性,不如`ref`直接。用户提到的繁琐在于每个变量都要单独用`ref`定义,这确实会增加代码量。但有没有办法在`<script setup>`中用`reactive`批量管理,同时保持模板的简洁呢?答案是肯定的,但需要注意响应式丢失的问题。例如,可以将相关变量分组到不同的`reactive`对象中,然后通过解构`toRefs`来暴露,这样既能减少`ref`的数量,又能保持响应性。不过,用户可能担心解构后的变量是否仍然保持响应式。这里需要解释`toRefs`的作用,它会将`reactive`对象的每个属性转换为`ref`,确保解构后的变量仍然是响应式的。这样在模板中可以直接使用变量名,而不需要通过对象属性访问。此外,用户可能没有意识到,在`<script setup>`中,可以将多个相关的状态组合到一个`reactive`对象中,然后通过解构`toRefs`来简化代码。例如,将所有的布尔状态放在一个`state`对象中,这样只需一个`reactive`和`toRefs`即可管理多个变量。还需要比较两种写法的优缺点。传统`setup()`函数虽然可以通过`toRefs`批量暴露,但需要手动返回所有变量,而`<script setup>`自动暴露顶层变量,减少了样板代码。然而,当变量较多时,单独使用`ref`可能显得冗长,此时结合`reactive`和`toRefs`可以优化代码结构。最后,需要给出具体的示例,展示如何在`<script setup>`中使用`reactive`和`toRefs`来简化变量定义,并说明注意事项,比如避免直接解构`reactive`对象导致响应式丢失,必须使用`toRefs`进行转换。总结来说,用户的问题集中在如何在使用`<script setup>`时更高效地管理多个变量,而解决方案在于合理使用`reactive`和`toRefs`的组合,既能减少代码量,又能保持响应式特性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/899279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐一个查看Windows文件夹大小的软件

最近笔记本越来越卡,C盘100G几乎全被占用,所以就想查看是哪个文件占用了C盘, 但是Windows自带的又不好用,于是再网上找了一下 https://windirstat.net/ 发现了这个软件,非常好用,一目了然,免费,可以安装也可以直接解压, 可以查看每个文件和文件夹的大小,占比, 按文件…

Copilot平替?本地部署DeepSeek-Coder V2并接入到VS Code

什么是 DeepSeek-Coder V2 DeepSeek-Coder-V2是DeepSeek团队推出的基于MoE架构的智能代码模型,支持338中编程语言,几乎覆盖所有主流和小众编程语言,一次能处理长达128K的代码文件。 Github 开源仓库地址:https://github.com/deepseek-ai/DeepSeek-Coder-V2 用过DeepSeek很多…

Builder-公用组建封装和 按引用传递 改变数据

@Entry@Componentstruct BuilderPage { // 组建内的 @Builder compButtonBuilder(icon:Resource,text:string,callback:()=>void){ Button() { Row({ space: 10 }) { Image(icon) .width(25) .height(25) Text(text) .f…

【第 8 期】搜索客 Meetup - Elasticsearch 的一些“双刃剑”特性

本次活动由 搜索客社区、极限科技(INFINI Labs) 联合举办,活动邀请到 INFINI Labs 搜索运维专家 金端 来分享 Elasticsearch 中一些典型的“双刃剑”特性,以及如何在实际使用中权衡和应对。欢迎预约直播观看 ~ 活动主题:Elasticsearch 的一些“双刃剑”特性 活动时间:202…

clion/idea/pycharm项目配置

环境搭建与配置 pycharm篇 markdown as root idea篇 clion篇构建 cmake -S src -B build $CMAKE_OPTIONS 编译 cmake --build 配置deployment,cmake(cmake配置编译目录,引用环境变量,cmake环境变量引用$CMAKE_OPTIONS) ccache配置 ccache弄一个gcc和g++的软链,放在PATH最…

web68笔记(+禁用print_r、highlight)

web68 打开就直接说 Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19 猜跟之前代码一致,加了过滤 然后这⾥还把print_r给禁了,⽤var_dump()吧 c=var_dump(scandir("/")); 还是在跟⽬录 flag.txt 既然hig…

健身相关

后仰?10次 如何管理自己的症状 急性期https://new.qq.com/rain/a/20210819A094EC00犀牛数据地点+纳税排名

文本弹窗选择

@Entry@Componentstruct TextPickerDialogPage { fruits: string[] = [苹果, 橘子, 香蕉, 鸭梨, 西瓜] @State selectedIndex: number = 0 build() { Column({ space: 50 }) { Text(this.fruits[this.selectedIndex]) .fontWeight(FontWeight.Bold) .…

AP csa FRQ Q1 Past Paper 五年真题汇总 2023-2019

Author(wechat): bigshuang2020 ap csa tutor, AP计算机科学a老师 国际教育编程老师, 擅长答疑讲解,带学生实践学习。热爱创作,作品:ap csa原创教案,真题梳理汇总,FRQ专题冲刺。2023 FRQ Question 1 This question involves the appointmentBook class, which provides me…

自带弹窗-》删除功能提示

@Entry@Componentstruct AlertDialogPage { build() { Column() { Button(删除) .backgroundColor(Color.Red) .onClick(() => { AlertDialog.show( { title: 删除该记录?, //弹窗标题 message: 删除…

ASE90N25-ASEMI工业电机专用ASE90N25

ASE90N25-ASEMI工业电机专用ASE90N25编辑:ll ASE90N25-ASEMI工业电机专用ASE90N25 型号:ASE90N25 品牌:ASEMI 封装:TO-247 批号:最新 最大漏源电流:90A 漏源击穿电压:250V RDS(ON)Max:26mΩ 引脚数量:3 沟道类型:N沟道MOS管、中低压MOS管 漏电流:ua 特性:N沟道MO…

温度转化和蟒蛇绘制

蟒蛇绘制 import turtle turtle.setup(650,360,600,200) turtle.penup() turtle.fd(-250) turtle.pendown() turtle.pensize(25) turtle.pencolor("pink") turtle.seth(-40) for i in range(4): turtle.circle(40,80) turtle.circle(-40,80) turtle.circle(40,80/2) …