- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
useChangeCase 是 VueUse 集成层(@Integrations)中针对change-case库的响应式封装,在 Vue 3 项目中可直接替代useCamelCase、usePascalCase、useSnakeCase、useSentenceCase、useCapitalize等一揽子历史函数。阅读本文后,你将掌握它的安装方式、基础用法、ref/getter 响应式接入、options 定制,以及其底层源码实现与类型设计,能够直接在表单输入、路由参数、组件 prop 等场景中实现“输入即转换”的字符串命名实时转换。
本文以仓库内 useChangeCase 参考文档 为骨架,并结合 核心实现、测试用例 与 实时 Demo 进行源码级纵深讲解。
功能定位:一个函数取代全部命名转换 composable
useChangeCase 是一个对change-case的响应式(reactive)封装。change-case是一个纯函数式的字符串大小写转换库,每个转换都是同步纯函数;而 useChangeCase 把它们接入 Vue 的响应式系统,使字符串转换结果以computed的形式自动跟随输入变化。
从文档与实现来看,它替代了此前 VueUse 中一批分散的 composable:useCamelCase、usePascalCase、useSnakeCase、useSentenceCase、useCapitalize等,全部收敛为一个按type参数切换转换策略的统一入口。相比逐一维护多个函数,这种做法让 API 面更小、类型更收敛、扩展新转换方法时也无需新增 composable。
安装与依赖说明
npm i change-case@^5需要安装的是作为 peer 依赖的change-case。查看 integrations 包配置,change-case被声明为可选 peerDependency(optional: true,版本^5),也就是说:只要你的项目里装了change-case,useChangeCase 就可以工作;未安装时它不会阻塞@vueuse/integrations的其他功能。在本仓库中,pnpm-workspace.yaml 的catalog:integrations里将change-case固定为^5.4.4,与该参考文档要求的 v5 主版本一致。
导入路径既可以是子路径,也可以走主入口:
import { useChangeCase } from '@vueuse/integrations/useChangeCase' // 子路径导入 import { useChangeCase } from '@vueuse/integrations' // 主入口(见 packages/integrations/index.ts 的 re-export)基础用法:传入字符串,返回可写 computed
最简单的调用是把普通字符串作为输入,此时返回的是一个WritableComputedRef<string>:
import { useChangeCase } from '@vueuse/integrations/useChangeCase' // `changeCase` 是一个 computed const changeCase = useChangeCase('hello world', 'camelCase') changeCase.value // helloWorld changeCase.value = 'vue use' changeCase.value // vueUse因为返回值是可写的 computed,给changeCase.value赋值会反向写入底层源字符串,然后再按当前转换类型重新产出。这相当于把“源文本”和“展示文本”绑定在同一个引用上,适合“用户输入原文、页面展示转换结果”的双向需求。
type参数支持的全部转换方法,与change-case导出的以Case结尾的函数一一对应(参考文档注释中列举如下):
// export { // camelCase, // helloWorld // capitalCase, // Hello World // constantCase, // HELLO_WORLD // dotCase, // hello.world // headerCase, // Hello-World // noCase, // hello world // paramCase, // hello-world // pascalCase, // HelloWorld // pathCase, // hello/world // sentenceCase, // Hello world // snakeCase, // hello_world // } from 'change-case'值得留意的是,参考文档注释里出现了headerCase、paramCase,而 测试用例 中实际覆盖的是trainCase与kebabCase(helloWorld → Hello-World、helloWorld → hello-world)。这源于change-case不同版本间的命名差异(v5 中headerCase/paramCase分别演变为trainCase/kebabCase)。由于 useChangeCase 是运行时动态收集所有以Case结尾的导出函数(见下文源码解析),因此具体可用方法完全取决于你安装的change-case版本,v5 下以测试覆盖的trainCase、kebabCase为准。
响应式接入:传入 ref,转换自动跟随
传入的input同样可以是一个ref,此时返回的 computed 会随源 ref 的变化实时重算:
import { useChangeCase } from '@vueuse/integrations/useChangeCase' import { shallowRef } from 'vue' const input = shallowRef('helloWorld') const changeCase = useChangeCase(input, 'camelCase', { delimiter: '-', }) changeCase.value // hello-World input.value = 'vue use' changeCase.value // vue-Use这是最典型的实战场景:input绑定到表单输入框,changeCase绑定到展示区或提交数据,用户在输入框敲一个字,转换结果就实时刷新一次,无需任何手动监听。在 Demo 文件 中,作者正是用shallowRef承载输入文本与当前选中的转换类型,配合一组 radio 按钮和文本输入框,实现了所见即所得的转换演示。
除了字符串与 ref,input还支持getter 函数。从 类型重载 可以看到:
- 传入
MaybeRef<string>(字符串或 ref)→ 返回WritableComputedRef<string>(可写) - 传入
MaybeRefOrGetter<string>(字符串、ref 或() => string)→ 返回ComputedRef<string>(只读)
传入 getter 时只读,这是合理的设计——getter 本身是只读数据源,没有可写回的“底层值”。
options 定制:调整分隔符等转换细节
第三个参数options用于定制change-case的转换行为,同样可以是MaybeRefOrGetter<Options>。最常用的选项是delimiter,用于自定义单词间的分隔符:
const changeCase = useChangeCase(input, 'camelCase', { delimiter: '-', })当设置delimiter: '-'后,单词分隔符从默认值改为-,例如helloWorld → hello-World、vue use → vue-Use。Options类型直接来自change-case(见 核心实现 的import type { Options } from 'change-case'),因此change-casev5 支持的其他选项(如splitRegexp、prefix、suffix等)在传给 useChangeCase 时同样有效,具体以所安装版本的Options类型定义为准。
源码实现解析:运行时收集 + 可写 computed
从 核心实现 可以看出三个关键设计:
1. 运行时动态收集转换函数
const changeCaseTransforms: any = /* @__PURE__ */ Object.entries(changeCase) .filter(([name, fn]) => typeof fn === 'function' && name.endsWith('Case')) .reduce((acc, [name, fn]) => { acc[name] = fn return acc }, {} as any)它并不硬编码方法列表,而是遍历change-case的全部导出,筛出“是函数且名字以Case结尾”的项。这意味着change-case新增任何转换方法,useChangeCase 都会自动获得支持,无需改代码。
2. 对type做校验
const typeRef = computed(() => { const t = toValue(type) if (!changeCaseTransforms[t]) throw new Error(`Invalid change case type "${t}"`) return t })type先经toValue解包(兼容 ref 与 getter),再查表校验;传入不存在的转换名会立即抛出Invalid change case type "..."错误,避免运行时静默失败。type本身也可以响应式变化——在 Demo 中切换 radio 按钮时,转换类型随之切换,这正是typeRef为 computed 带来的能力。
3. 按输入形态分叉为可写 / 只读 computed
if (typeof input === 'function') return computed(() => changeCaseTransformstypeRef.value, toValue(options))) const text = deepRef(input) return computed<string>({ get() { return changeCaseTransformstypeRef.value) }, set(value) { text.value = value }, })input是 getter 函数 → 返回只读 computed,每次读取时执行toValue(input)取值转换;- 否则先把
input(字符串或 ref)统一包装为deepRef,再返回带get/set的可写 computed:get执行转换,set把新值写回源 ref,实现双向绑定。
此外,整个函数标注了/* @__NO_SIDE_EFFECTS__ */,纯函数、无副作用,便于打包器做 tree-shaking 与副作用消除,符合 integrations 包配置 中"sideEffects": false的声明。
类型系统:从change-case导出中推导合法转换名
参考文档给出了完整的 TypeScript 类型声明,它用条件类型与映射类型从change-case的真实导出中推导出合法参数集合:
type EndsWithCase<T> = T extends `${infer _}Case` ? T : never type FilterKeys<T> = { [K in keyof T as K extends string ? K : never]: EndsWithCase<K> } type ChangeCaseKeys = FilterKeys<typeof changeCase> export type ChangeCaseType = ChangeCaseKeys[keyof ChangeCaseKeys] export declare function useChangeCase( input: MaybeRef<string>, type: MaybeRefOrGetter<ChangeCaseType>, options?: MaybeRefOrGetter<Options> | undefined, ): WritableComputedRef<string> export declare function useChangeCase( input: MaybeRefOrGetter<string>, type: MaybeRefOrGetter<ChangeCaseType>, options?: MaybeRefOrGetter<Options> | undefined, ): ComputedRef<string>EndsWithCase<T>模板字面量类型:只保留以Case结尾的字符串键;FilterKeys<T>:把change-case的所有导出键过滤为字符串且以Case结尾的键;ChangeCaseType:取过滤后键的联合类型,即'camelCase' | 'capitalCase' | 'constantCase' | ...。
这意味着 TypeScript 能在编译期就拦截非法的转换类型名,与源码中运行时的throw new Error校验形成“编译期 + 运行期”双重保障。MaybeRefOrGetter语义由 VueUse 提供,统一了“值 / ref / getter”三种传参形态。
测试验证:全量转换方法与四种调用形态
测试用例 用一张映射表锁定了每种转换方法在helloWorld与vue use两个输入下的期望输出,并对capitalCase、constantCase、dotCase、trainCase、noCase、kebabCase、pascalCase、pascalSnakeCase、pathCase、sentenceCase、snakeCase逐一跑四组用例:
- base:字符串直接传入(
useChangeCase(helloWorld, key)); - ref:
ref传入(useChangeCase(input, key)); - options:传入
{ delimiter: '-' },验证输出变为Hello-World、HELLO-WORLD等带-分隔的形态; - function:getter 传入(
useChangeCase(() => helloWorld, key))。
同时每组都验证了可写语义——changeCase.value = vueuse之后再次读取应得到对应转换结果。这套测试既是行为契约,也可作为你集成时的期望输出对照表。
实战建议与最佳实践
综合文档、源码与测试,使用 useChangeCase 时建议遵循以下几点:
- 输入形态决定返回形态:需要双向绑定(如输入框 + 实时展示)时传字符串或
ref,拿到可写 computed;只需要单向派生时传 getter,语义更清晰且为只读。 - 用
type的响应式能力做动态切换:type支持 ref/getter,可在 UI 上提供转换方式切换(参考 Demo 的 radio 交互),无需重建引用。 - 依赖版本保持 v5:
change-case需要^5(本仓库固定^5.4.4),转换方法命名以你实际安装的版本导出为准(注意headerCase/paramCase与trainCase/kebabCase的版本差异)。 - 让类型替你把关:
type参数有ChangeCaseType联合类型约束,传非法值在编译期即报错;同时源码运行期校验兜底,两者都不会放行未知转换名。 - 小尺寸、无副作用:该函数标注
@__NO_SIDE_EFFECTS__且所在包sideEffects: false,按需导入不会给 bundle 增加负担,可放心在组件中高频使用。
如果你需要在 Vue 3 中为任意字符串做实时、响应式的命名风格转换,useChangeCase 就是那个“一个函数覆盖全部 Case 转换”的最终答案——配合本仓库的 实现源码、测试契约 与 交互 Demo,从接入到原理可以一次吃透。
- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
相关推荐
静态网站分享到社交平台总被"吞"?5步用Instatic配好元标签与分享图
静态网站分享到社交平台总被"吞"?5步用Instatic配好元标签与分享图 在微信群或论坛里丢出一条链接,对方看到的往往只有一串干巴巴的网址——没有标题、没有配
CMS后端前端VueUse useChangeCase:让 change-case 在 Vue 3 中响应式生效的集成指南
VueUse useChangeCase:让 change case 在 Vue 3 中响应式生效的集成指南 useChangeCase 是 VueUse 集成
前端10种字符串格式一键转换:Change Case让文本处理效率提升300%的终极工具
10种字符串格式一键转换:Change Case让文本处理效率提升300%的终极工具 在日常开发和文本处理中,我们经常需要在不同的字符串格式之间进行转换,比如将
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考