Less无真正模式匹配,仅通过when守卫模拟分支;.btn(@state) when (@state = hover)会报错,因未覆盖loading、12px等其他输入类型,且缺少default()兜底,导致编译时undefined mixin错误。

Less 没有真正的模式匹配(Pattern Matching),所谓“重载”只是靠 when 守卫条件模拟出来的分支逻辑;不显式写全所有输入类型分支,编译时就会报 undefined mixin 错误。
为什么 .btn(@state) when (@state = hover) 会报错?
因为 Less 编译器不会自动兜底——它只按顺序找第一个满足 when 条件的 mixin,其余全忽略。如果你只写了 .btn(@state) when (@state = hover),但调用时传了 loading 或 12px,就直接失败。
- 必须覆盖所有可能传入的类型:字符串、数字、关键字、单位值,否则编译中断
-
isstring(@val)和isnumber(@val)要分开判断,不能混在同一个when里 - 含子串的字符串需用
str-index(@val, "loading") > 0,而非简单@val = "loading"(避免漏掉loading-sm) - 最后一定要加
.btn(@state) when (default())收尾,这是唯一能捕获未被前面条件覆盖的输入的方式
如何安全支持 .btn(8px) 和 .btn(8px, 16px) 这类变参?
Less 不允许仅靠参数个数区分同名 mixin:.btn(@a) 和 .btn(@a, @b) 写在一起,后者会静默覆盖前者,且不报错——这很危险。
- 统一收口为单参数:
.btn(@args),再用extract(@args, 1)、extract(@args, 2)拆解 - 或改用 map:
.btn({ padding: 8px, margin: 0 }),定义中用@rest: @arguments[0]; @padding: @rest[padding] - 别在 mixin 名后留空括号写多个定义,比如
.pad() { }和.pad(@v) { }——这种“重载”在 Less 里无效
状态和尺寸为什么要正交拆分?
把 @size 和 @state 塞进一个 mixin 里,比如 .button(@size, @state),会导致组合爆炸:medium + hover、large + disabled……维护成本指数级上升。
立即学习“前端免费学习笔记(深入)”;
- 尺寸单独用 map 管理:
@button-sizes: { small: (h: 24px, p: 0 8px), medium: (h: 32px, p: 0 12px) } - 状态用 guard 分离:
.button-state(@s) when (@s = hover) { background: darken(@bg, 10%); } - 调用时链式组合:
.button-base(); .button-size(medium); .button-state(hover);,清晰、可预测、易调试 - 这样还能自由叠加,比如
.button-size(small); .button-state(disabled); .button-theme(inverted);
最容易被忽略的一点:所有“匹配”都发生在编译时
你在 HTML 里动态加 class="btn--loading",不会触发任何 when 分支——所有 CSS 都已在编译阶段静态展开完毕。所谓“响应”,只是你提前预设好了所有可能的状态输出。
这意味着:如果你漏写了 isdimension(@val) 分支,而设计稿突然要求 .btn(1.5rem),就得立刻补上,而不是等运行时报错;也意味着,别指望靠 JS 控制传给 mixin 的值来实现运行时切换——那得换 CSS 自定义属性或 JS-in-CSS 方案。


















