跳到主要内容

概览

@weapp-tailwindcss/merge 是面向小程序生态的 tailwind-merge 运行时封装。它在保留原库全部 API 的基础上,对类名做了小程序合法化转义,并与 weapp-tailwindcss 编译期插件联动,提供稳定的跨端开发体验。

为什么要使用 merge 运行时

  • 动态类名更安全:在组件里根据状态拼接类名时,twMerge 会自动剔除冲突项,确保最终样式一致。
  • 小程序专属转义:运行时会把诸如 [#ececec][length:24rpx] 等非法字符转成小程序可识别的占位符,并在编译期再还原。
  • 覆盖多个 Tailwind CSS 主版本@weapp-tailwindcss/merge 针对 tailwindcss@4(基于 tailwind-merge@3),而 @weapp-tailwindcss/merge-v3 保持对 tailwindcss@3 的长期支持,两者 API 完全一致。
  • 保留原生 APItwMergetwJoinextendTailwindMergecreateTailwindMerge 等函数与原版完全一致,迁移成本低。
与原库的差异

为了适配小程序,@weapp-tailwindcss/merge 会在运行时做两件事:

  1. 先调用 @weapp-core/escape 对字符串「去转义」,把已经被编译期处理过的值还原为标准 Tailwind 类名;
  2. 调用原始的 tailwind-merge 完成合并后,再重新转义一次,交给小程序端运行。

如果你在纯 Web 项目中使用,请参考下方的「多端项目」章节配置。

运行时矩阵

包名适用场景说明
@weapp-tailwindcss/runtime共享依赖封装 escape/unescape、clsxweappTwIgnore,被下游包复用
@weapp-tailwindcss/mergetailwindcss@4基于 tailwind-merge@3,默认入口
@weapp-tailwindcss/merge-v3tailwindcss@3基于 tailwind-merge@2,专为老项目保留
@weapp-tailwindcss/cvaclass-variance-authority自动 escape 的 cva() 运行时
@weapp-tailwindcss/variantstailwind-variants提供 tv/cn 等扩展能力

安装

npm i @weapp-tailwindcss/merge

适用于 tailwindcss@4 的项目。若你仍在维护 tailwindcss@3,请改为安装 @weapp-tailwindcss/merge-v3

npm i @weapp-tailwindcss/merge-v3

快速上手

import { twMerge } from '@weapp-tailwindcss/merge'

const buttonClass = twMerge(
'px-2 py-1 bg-red hover:bg-dark-red',
'p-3 bg-[#B91C1C]'
)

// => 'hovercbg-dark-red p-3 bg-_hB91C1C_'

同样的写法在 Web 端会得到 hover:bg-dark-red p-3 bg-[#B91C1C]。在小程序里之所以出现 _h_ 等占位符,是因为运行时完成了转义。weapp-tailwindcss 插件会在编译阶段把这些占位符还原成合法类名。

与 weapp-tailwindcss 的编译期配合

  • weapp-tailwindcss 默认把 twMergetwJoincva 标记为「无需再次转义」的调用点,如果你自定义了函数名(例如把 twMerge 重命名为 cn),需要在配置里补充 ignoreCallExpressionIdentifiers

  • 对于模板字符串,可以使用 weappTwIgnore 标签跳过编译期处理:

    import { weappTwIgnore } from '@weapp-tailwindcss/merge'

    const raw = weappTwIgnore`text-[#123456]`

    这个 helper 实际上就是 String.raw,但它可以让插件准确识别并跳过转义。

tailwind-variants 快速体验

@weapp-tailwindcss/variants 提供了 tailwind-variants 的运行时封装,在小程序环境中同样可以使用 tv/cn 输出带转义的类名:

import { tv } from '@weapp-tailwindcss/variants'

const badge = tv({
base: 'inline-flex items-center rounded-full px-2 text-xs font-semibold',
variants: {
tone: {
neutral: 'bg-[#F4F4F5] text-[#18181B]',
success: 'bg-[#DCFCE7] text-[#166534]',
danger: 'bg-[#FEE2E2] text-[#B91C1C]',
},
},
defaultVariants: {
tone: 'neutral',
},
})

badge({ tone: 'success' })
// => 'inline-flex ... bg-_b_hDCFCE7_B text-_b_h166534_B'

更多组合用法、cn 聚合器以及逃逸策略见后文的 cva 与 tailwind-variants 支持 章节。

多端项目:按需控制转义

create 工厂允许你为不同运行时定制 escape 策略:

import { create } from '@weapp-tailwindcss/merge'

const { twMerge: mergeForMiniProgram } = create()
const { twMerge: mergeForWeb } = create({
escape: false,
unescape: false,
})

mergeForMiniProgram('text-[#ececec]', 'text-[#ECECEC]') // → 'text-_b_hECECEC_B'
mergeForWeb('text-[#ececec]', 'text-[#ECECEC]') // → 'text-[#ECECEC]'
  • escape: false 表示结果保持原样(适合 Web 或同构渲染)。
  • unescape: false 可跳过运行前的「反转义」,用于确保输入不会被改写。
  • 如果只想自定义映射表,传入 escape: { map: { '#': '__hash__' } } 即可;运行时会把自定义映射与默认映射合并,保证编译期和运行时的行为一致。

在线体验

实时编辑器
function () {
  return <MergeDemo/>
}
结果
Loading...

上方示例允许切换「禁用 escape/unescape」,用来对比运行时转义前后的差异。