资讯动态

掌握 VueUse `useToggle`:在 airi 项目中编写优雅的布尔状态切换逻辑

发布时间:2026/9/10 12:18:42 来源:尧图企业网站定制
掌握 VueUseuseToggle在 airi 项目中编写优雅的布尔状态切换逻辑【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi导读useToggle是 VueUse 中最常用的工具函数之一它把「布尔值切换」这一高频操作封装为一个简洁、类型安全且支持自定义真/假值的组合式函数。本文将结合 airi 仓库中 useToggle 参考文档 与 use-theme.ts 等真实源码实现完整讲解其两种调用形态、自定义值、事件绑定陷阱与类型声明帮助你写出更简洁、可维护的 Vue 状态切换代码。一、为什么需要useToggle从「重复样板代码」到「一行切换」在 Vue 应用中开关类状态如侧边栏展开、弹窗显示、深色模式无处不在。手写版本往往长这样const visible ref(false) function toggleVisible() { visible.value !visible.value } function setVisible(value: boolean) { visible.value value }而useToggle将上述逻辑压缩为一次调用import { useToggle } from vueuse/core const [value, toggle] useToggle()这一设计思路与 airi 仓库.agents/skills/vueuse-functions/SKILL.md中声明的技能宗旨完全一致优先使用 VueUse 组合式函数而非自造代码以提升可读性、可维护性与性能。在 SKILL.md 的功能表中useToggle被归类在 Utilities 分类下描述为 “A boolean switcher with utility functions”调用规则为AUTO——即在合适的场景下应自动使用。二、两种调用形态解构元组 与 接收 refuseToggle的重载设计让它可以同时服务「全新状态」与「既有状态」两种场景。形态一不传参数返回[value, toggle]元组import { useToggle } from vueuse/core const [value, toggle] useToggle()此时value是一个ShallowRefbooleantoggle是一个切换函数。两者通过数组解构返回这与 Vue 3 中v-model常见写法一样直观。形态二传入 ref返回纯切换函数当你已经有一个 ref例如由useDark生成的isDarkuseToggle会直接接管这个 ref 并只返回一个切换函数不再重复创建状态import { useDark, useToggle } from vueuse/core const isDark useDark() const toggleDark useToggle(isDark)这是 airi 项目中实际采用的模式。在 packages/ui/src/composables/use-theme.ts 中主题模块正是这样把「状态」与「切换动作」绑定在一起import { useDark, useToggle } from vueuse/core import { LocalStorageShim } from ../utils const isDark useDark({ disableTransition: true, // NOTICE: for histoire, used in packages/stage-ui, localStorage global variable exists but storage.getItem is not a function wil // thrown, here we added LocalStorageShim to avoid this issue, and it will fallback to real localStorage when its available. storage: localStorage in globalThis localStorage ! null getItem in localStorage typeof localStorage.getItem function ? localStorage : new LocalStorageShim(), }) const toggleDark useToggle(isDark) export function useTheme() { return { isDark, toggleDark, } }注意这里的两个细节传入 ref 时返回的是函数而非元组因此useTheme()解构出的是{ isDark, toggleDark }toggleDark直接可用作事件处理器useToggle不会创建新的状态它读写的就是传入的isDark保证了「读取状态」与「切换状态」指向同一个响应式源。两种形态的判别方式useToggle通过第一个参数的类型来区分行为参数是一个RefT返回(value?: T) T即仅一个切换函数参数缺失或为普通值返回[ShallowRefT, (value?: T) T]元组。这与 VueUse 许多函数的「ref 优先」设计一脉相承也是该技能文档建议「先检查 VueUse 是否已有现成函数」的原因。三、切换函数的三类调用方式无论哪种形态返回的切换函数都支持三种调用方式const [value, toggle] useToggle() toggle() // 在 true 与 false 之间切换 toggle(true) // 强制设置为指定值 toggle(false) // 强制关闭 // 切换函数会返回切换后的新值便于链式使用 const newValue toggle() // 返回切换后的最新值返回值的新值语义toggle()在翻转后会返回新值这意味着可以直接把它接进其它逻辑例如同步到日志、发送到服务端或作为其它函数入参const [muted, toggleMuted] useToggle() // 每次切换后立刻拿到最新状态 watchEffect(() console.log(muted , muted.value)) const latest toggleMuted() // latest 与 muted.value 一致这一「返回值 新值」的约定让useToggle比手写value.value !value.value更具表达力你既能拿它当赋值器又能拿它当读取器。四、自定义真值与假值不止于 true / falseuseToggle并不局限于布尔类型。通过UseToggleOptions中的truthyValue与falsyValue可以让状态在两个自定义值之间切换例如字符串枚举import { useToggle } from vueuse/core const [value, toggle] useToggle(on, { truthyValue: on, falsyValue: off, }) toggle() // off toggle() // on这在需要把 UI 状态直接映射为接口参数如open/closed、enabled/disabled时非常有用省去了额外的映射层。自定义值也可以是响应式的truthyValue与falsyValue的类型是MaybeRefOrGetter意味着你可以传入 ref 或 getter让「目标真值/假值」本身动态变化import { useToggle } from vueuse/core import { ref } from vue const truthy ref(yes) const falsy ref(no) const [value, toggle] useToggle(yes, { truthyValue: truthy, falsyValue: falsy, })此时如果外部将truthy.value改为是则value的判等逻辑会跟随新的目标值。泛型推导从类型声明可以看出Truthy与Falsy是两个独立泛型最终值类型T Truthy | Falsyexport interface UseToggleOptionsTruthy, Falsy { truthyValue?: MaybeRefOrGetterTruthy falsyValue?: MaybeRefOrGetterFalsy }这意味着真值与假值不必是同一类型尽管实践中通常保持一致TypeScript 会依据传入的 options 自动推断value与toggle的参数/返回值类型获得完整的编译期校验。五、事件绑定的陷阱第一个参数是覆盖值useToggle文档特别标注了一个 Caution切换函数把第一个参数视为覆盖值override value。如果在模板中把函数直接传给事件浏览器会把事件对象$event当作第一个参数传入导致行为异常!-- caution: $event will be passed in -- button clicktoggleDark / !-- recommended to do this -- button clicktoggleDark() /原因是 DOM 事件回调会以event作为首个实参调用处理函数toggleDark(event)等价于「将主题强制设置为事件对象」——而事件对象恒为 truthy于是主题永远被强制切换为真值一侧再也无法翻转回来。airi 仓库中的所有使用点都严格遵守了这一约定。例如 apps/component-calling/src/App.vue 中的深色模式按钮button text-lg click() toggleDark() div v-ifisDark i-solar:moon-stars-bold-duotone / div v-else i-solar:sun-bold / /button注意这里同时展示了两种推荐写法click() toggleDark()用箭头函数包一层显式调用且不传参模板中依据isDark切换图标i-solar:moon-stars-bold-duotone与i-solar:sun-bold图标本身即是对状态的可视化反馈。在桌面端 apps/stage-tamagotchi/src/renderer/components/stage-islands/controls-island/index.vue 中控制岛的深色模式按钮同样使用了click() toggleDark()见其第 306 行toggleDark来自useTheme()解构第 40 行与 component-calling 保持一致的调用约定。为什么不直接用clicktoggleDark即使你的切换函数内部对参数做了容错直接透传函数也会让「事件对象作为覆盖值」这一隐式行为成为隐患而clicktoggleDark()或click() toggleDark()则从语法层面杜绝了误传代码意图一目了然。六、类型声明全解useToggle的完整类型签名如下理解它有助于你正确使用泛型与重载export type ToggleFn (value?: boolean) void export type UseToggleReturn [ShallowRefboolean, ToggleFn] | ToggleFn export interface UseToggleOptionsTruthy, Falsy { truthyValue?: MaybeRefOrGetterTruthy falsyValue?: MaybeRefOrGetterFalsy } export declare function useToggleTruthy, Falsy, T Truthy | Falsy( initialValue: RefT, options?: UseToggleOptionsTruthy, Falsy, ): (value?: T) T export declare function useToggle Truthy true, Falsy false, T Truthy | Falsy, ( initialValue?: T, options?: UseToggleOptionsTruthy, Falsy, ): [ShallowRefT, (value?: T) T]逐行拆解声明要素含义ToggleFn默认布尔场景下的切换函数类型(value?: boolean) voidUseToggleReturn两种形态的返回类型联合元组 或 纯函数UseToggleOptionsTruthy, Falsy自定义真值/假值选项二者均可为MaybeRefOrGetter值、ref 或 getter重载一initialValue: RefT传入 ref 时返回(value?: T) T读写的是同一个 ref重载二initialValue?: T不传或传普通值时返回[ShallowRefT, (value?: T) T]默认Truthy true、Falsy false泛型T Truthy \| Falsy状态值的类型统一为真值与假值类型的并集两个重载都遵循同样的规则切换函数的可选参数value是覆盖值——传了就强制设置不传则取反。返回值始终是新值。七、实战组合useToggleuseDark构建全端主题系统airi 将useToggle与useDark组合封装成useTheme()并在多个应用间复用是理解其工程价值的完整范例封装层packages/ui/src/composables/use-theme.tsuseDark负责「读取/持久化主题状态」含 localStorage 能力探测与 shim 兜底useToggle(isDark)负责「生成切换动作」对外暴露{ isDark, toggleDark }Web 演示层apps/component-calling/src/App.vue 与 apps/stage-web/src/App.vue消费useTheme()在 UI 上呈现当前主题并绑定切换桌面端层apps/stage-tamagotchi/src/renderer/App.vue 与 controls-island/index.vue同一套useTheme在 Electron 渲染进程中复用实现控制岛上的明暗主题按钮布局组件层packages/stage-layouts/src/components/Layouts/HeaderLink.vue 等组件通过const { isDark: dark } useTheme()只读消费主题态用于驱动背景与前景的视觉配色。该模式的价值在于状态读写点始终只有一个。无论toggleDark被多少个组件引用它操作的始终是useDark创建的同一个 ref杜绝了「各组件各自维护一份主题布尔值」导致的失步问题。八、最佳实践小结优先复用凡是「布尔或双值状态 切换」的需求先查 VueUse 是否有现成函数参见 SKILL.md 的功能表再决定是否手写传 ref 而非复制状态若状态已存在把 ref 交给useToggle让它只负责生成切换函数避免状态分裂模板中永远用clicktoggleDark()或箭头函数包裹防止事件对象被当作覆盖值传入需要自定义值时用 optionstruthyValue/falsyValue支持值、ref、getter可配合泛型获得类型推导利用返回值toggle()返回新值可无缝衔接日志、接口调用等后续逻辑封装成 composable像 airi 的useTheme()一样把「状态 切换 持久化」收敛为一个可复用函数跨 Web / Electron 端共享。掌握了useToggle的两种形态、返回值语义与事件陷阱后你会发现绝大多数「开关类」逻辑都可以在一两行内优雅地表达这正是 VueUse 组合式函数设计的核心目标——用最小的心智负担完成最频繁的状态操作。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价