- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
logicNot是 VueUse 数学扩展包@vueuse/math提供的逻辑组合函数之一,其作用是对传入的 ref、普通值或 getter 函数取逻辑非(!),并返回一个类型为ComputedRef<boolean>的响应式计算结果。本文将以 logicNot 官方文档 为核心骨架,结合 源码实现 与 单元测试 深入讲解其工作原理、与whenever的经典组合用法,以及它与logicAnd、logicOr构成的完整逻辑函数家族,帮助你在 Vue 3 组合式 API 场景中精准驾驭“反向条件”的响应式编程。
一、功能定位:为 ref 而生的 NOT 条件
logicNot解决的是一类非常常见但容易写脏的 Vue 响应式需求:当某个 ref 的值由真变假(或由假变真)时,触发一段逻辑。直接写!a.value只能拿到一次性快照,无法保持响应式;而logicNot(a)返回的ComputedRef会随着a的变化持续重算,天然融入 Vue 的响应式依赖追踪体系。
在 VueUse 的官方分类中,logicNot属于@Math类别,文档 frontmatter 中声明了别名alias: not,即历史上它也曾以not命名导出(详见下文“别名与迁移”一节)。
import { whenever } from '@vueuse/core' import { logicNot } from '@vueuse/math' const a = ref(true) whenever(logicNot(a), () => { console.log('a is now falsy!') })这是 官方文档 中的标准用法:whenever监听logicNot(a)这个 computed 值,一旦它变为 truthy(即a变为 falsy),回调便会被触发。整个链路完全由响应式系统驱动,无需手动订阅与清理。
二、安装与引入
logicNot与logicAnd、logicOr、useSum、useAverage等一起打包在@vueuse/math子包中,同时依赖@vueuse/core(示例中的whenever来自 core)。按照 packages/math/README.md 的说明安装:
npm i @vueuse/math @vueuse/core引入方式与官方文档保持一致:
import { logicNot } from '@vueuse/math'所有 math 工具统一从 packages/math/index.ts 的入口聚合导出,其中包含export * from './logicNot'一行,因此从包根路径导入即可,无需深链到具体目录。
三、源码剖析:computed + toValue 的极简实现
logicNot的完整实现只有短短几行,但它精准体现了 VueUse 工具函数的通用设计范式。以下为 packages/math/logicNot/index.ts 的完整源码:
import type { ComputedRef, MaybeRefOrGetter } from 'vue' import { computed, toValue } from 'vue' export function logicNot(v: MaybeRefOrGetter<any>): ComputedRef<boolean> { return computed(() => !toValue(v)) }1. 入参类型:MaybeRefOrGetter<any>
函数唯一参数的类型是MaybeRefOrGetter<any>,这是 Vue 3.3+ 引入的宽松入参类型,它涵盖三类输入:
| 输入形态 | 示例 | 处理方式 |
|---|---|---|
| 普通值 | logicNot(true) | toValue直接返回原值 |
| Ref | logicNot(ref(true)) | toValue自动解包,读取.value |
| Getter 函数 | logicNot(() => true) | toValue调用函数取返回值 |
正因为接受“值 / ref / getter”三种形态,logicNot既可以用在静态场景(对普通布尔值取反),也可以用在动态场景(包裹响应式 ref),而调用方无需关心底层形态差异。
2. 核心机制:computed 惰性重算
返回值是computed(() => !toValue(v))。computed保证了两个关键性质:
- 惰性求值:只有被读取时(例如被模板、
watch、whenever或toValue访问)才会真正计算; - 依赖追踪:当
v是 ref 或 getter 内部引用了响应式状态时,toValue的读取行为会被 Vue 收集为依赖,v变化时该 computed 自动失效并重算。
从源码结构看,这正是logicNot与!a.value这类手写表达式最本质的区别:前者是响应式数据流中的一等公民,后者是一次性快照。
3. 语义细节:JS 真值(truthy/falsy)而非严格布尔
!toValue(v)使用的是 JavaScript 的通用真值语义,因此它不仅处理true/false,还覆盖了所有 falsy 值。这一点被 单元测试 明确验证:
// falsy 输入 -> 返回 true expect(toValue(logicNot(shallowRef(false)))).toBe(true) expect(toValue(logicNot(shallowRef('')))).toBe(true) expect(toValue(logicNot(shallowRef(0)))).toBe(true) // truthy 输入 -> 返回 false expect(toValue(logicNot(shallowRef(true)))).toBe(false) expect(toValue(logicNot(shallowRef('foo')))).toBe(false) expect(toValue(logicNot(shallowRef(1)))).toBe(false)测试覆盖了 ref、普通值、getter 三种输入形态,例如logicNot(() => 0)返回true、logicNot('foo')返回false。这意味着logicNot可用于判断“空字符串、数字 0、null、undefined、NaN等 falsy 状态”,而不仅仅局限于布尔标志位。
四、实战用法:与 whenever 的组合模式
logicNot最经典的搭档是 VueUse 的whenever,用于在某个 ref 变为 falsy 时执行副作用。官方示例:
import { whenever } from '@vueuse/core' import { logicNot } from '@vueuse/math' const a = ref(true) whenever(logicNot(a), () => { console.log('a is now falsy!') })这段代码等价于手写watch(() => !a.value, cb),但语义更直白、可读性更高,而且logicNot的返回值本身就是ComputedRef<boolean>,可以直接传给watch、watchEffect、whenever等任何接受响应式数据源的 API。
典型场景一:表单校验的“反向提示”
import { logicNot } from '@vueuse/math' import { whenever } from '@vueuse/core' const email = ref('') const isValid = computed(() => /\S+@\S+\.\S+/.test(email.value)) // 邮箱从合法变为不合法时,立即提示 whenever(logicNot(isValid), () => { showError.value = true })注意这里logicNot的入参是另一个ComputedRef,再次印证了MaybeRefOrGetter的兼容性——computed 同样属于 ref 的一种。
典型场景二:条件渲染与样式切换
const loading = ref(true) // 模板中直接使用,响应式驱动 UI // v-if="logicNot(loading)" 等价于 v-if="!loading"不过需要说明:模板里直接用!loading即可,logicNot的价值更多体现在需要把“取反后的条件”作为值传递给其他组合式函数、watch 数据源或复用于多处时,避免重复编写!xxx.value表达式,也让逻辑命名更具可读性。
五、逻辑函数家族:logicNot / logicAnd / logicOr
logicNot并非孤立存在,它与logicAnd、logicOr共同构成 VueUse 的响应式布尔逻辑家族,三者实现高度同构。对照 logicAnd 源码 与 logicOr 源码:
// logicAnd:全部为 truthy 才返回 true export function logicAnd(...args: MaybeRefOrGetter<any>[]): ComputedRef<boolean> { return computed(() => args.every(i => toValue(i))) } // logicOr:任一为 truthy 即返回 true export function logicOr(...args: MaybeRefOrGetter<any>[]): ComputedRef<boolean> { return computed(() => args.some(i => toValue(i))) }| 函数 | 运算 | 入参形态 | 返回 | 文档别名 |
|---|---|---|---|---|
logicNot(v) | !toValue(v) | 单个MaybeRefOrGetter | ComputedRef<boolean> | not |
logicAnd(...args) | 全部 truthy | 可变参数MaybeRefOrGetter[] | ComputedRef<boolean> | and |
logicOr(...args) | 任一 truthy | 可变参数MaybeRefOrGetter[] | ComputedRef<boolean> | or |
三者均以@__NO_SIDE_EFFECTS__注解标记为无副作用纯函数(便于摇树优化与 SSR 分析),且都通过computed保持响应式。从 logicAnd 文档 和 logicOr 文档 的 frontmatter 可以看到,官方将三者用related字段互相关联,建议在需要组合布尔条件时直接混用:
import { logicAnd, logicOr, logicNot } from '@vueuse/math' import { whenever } from '@vueuse/core' const isAdmin = ref(false) const isLoggedIn = ref(true) const isBanned = ref(false) // 登录且未被封禁 且(是管理员 或 非游客) whenever( logicAnd(isLoggedIn, logicNot(isBanned), logicOr(isAdmin, logicNot(ref('guest')))), () => { /* 放行逻辑 */ }, )logicAnd、logicOr接受可变参数列表,可直接把多个 ref 一次性传入,而logicNot负责对其中任一条件单独取反,三者组合可以构建任意复杂的响应式布尔表达式,且全程保持声明式、可读、无手动订阅。
六、别名与迁移:not → logicNot
在 packages/math/logicNot/index.ts 的末尾,保留了历史别名导出:
/** @deprecated use `logicNot` instead */ export const not = logicNot即早期版本中该函数以not命名导出,现已被logicNot取代,not仅作为向后兼容的弃用别名保留。logicAnd、logicOr也存在对应的弃用别名and、or。因此:
- 新代码请统一使用
logicNot; - 若在旧代码中见到
import { not } from '@vueuse/math',其行为与logicNot完全一致,但应尽快迁移; - 文档 frontmatter 中的
alias: not正是为文档站点链接与历史引用提供的别名登记。
七、注意事项与边界
- 返回类型恒为
ComputedRef<boolean>:即使入参是普通值(如logicNot(0)),返回值也是 computed,需要用.value、模板解包或toValue()读取,不可直接当布尔量比较。 - 真值语义而非严格类型:
logicNot遵循 JavaScript 真值规则,''、0、null、undefined、NaN都会被取反为true。若需要严格的布尔比较,应在入参侧先做归一化(如computed(() => a.value === true))。 - getter 形态的响应式来源:当传入
() => someRef.value > 0这类 getter 时,toValue执行函数期间读取的响应式状态会成为 computed 的依赖,同样具备响应式更新能力;但 getter 本身不应包含副作用,否则每次重算都会重复执行。 - 无清理负担:
logicNot本身不注册任何监听器或副作用,其响应式更新完全由 Vue 的computed机制托管,组件卸载时自动回收,无需手动 dispose。
结语
logicNot是 VueUse 数学扩展包中最“小而美”的工具之一:三行核心代码,借助MaybeRefOrGetter、toValue与computed三大 Vue 原语,把“对响应式值取反”这一高频需求封装成可组合、可复用、可测试的纯函数。配合whenever做反向条件触发、与logicAnd/logicOr组合构建复杂布尔逻辑,它能让你的 Vue 3 代码在条件表达层面同样保持声明式与可读性。若想进一步验证其行为细节,可直接阅读仓库内的 源码、测试用例 以及 logicAnd、logicOr 的配套文档。
- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
相关推荐
深入 VueUse logicNot:为 ref 状态构建响应式 NOT 条件,实现组件状态的下降沿触发
深入 VueUse logicNot:为 ref 状态构建响应式 NOT 条件,实现组件状态的下降沿触发 本文是 airi 仓库内置 .agents/skill
AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染VueUse @vueuse/math useMin:响应式 Math.min 组合式函数完全指南
VueUse @vueuse/math useMin:响应式 Math.min 组合式函数完全指南 useMin 是 VueUse @vueuse/math 扩
前端airi 项目中的 refDebounced 实战:用 VueUse 为响应式 Ref 做防抖的完整指南
airi 项目中的 refDebounced 实战:用 VueUse 为响应式 Ref 做防抖的完整指南 refDebounced 是 VueUse 响应式(R
AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考