0

我正在尝试在 LESS 中制作可变参数 mixin。为此,我对 mixin 使用以下语法:

.mixin (@a; @rest...) {
    // @rest is bound to arguments after @a   
    // @arguments is bound to all arguments 
}

但我不知道如何操作@rest和读取mixin的最后一个参数。

这是我的代码:

.color () { }

.color (@shade) {
    #id {
        background-color : rgb(@shade, @shade, @shade);
    }
}

.color (@shade, @rest...) {
    #id {
        background-color : rgb(@shade, @shade, @shade);
    }
    .color(@rest);
}

.color(200, 160);

正如你所猜测的,这个 mixin 应该检查整个参数列表,并<div id="id">使用对应于 mixin 的最后一个参数(在本例中为 rgb(160, 160, 160))的灰色阴影为 my 的背景着色。

但是当我用 less-1.4.1.js 编译这段代码时,我得到了以下错误:

SyntaxError: error evaluating function `rgb`: 
color functions take numbers as parameters

那么如何获取mixin的第二、三、四...参数呢?

非常感谢您的建议,周末愉快!


编辑

工作得很好,非常感谢!

不过我想问另一个问题。假设我的 mixin 是可变参数的,它需要至少一个与其余参数(例如字符串或其他数字)无关的参数,但必须对其进行处理,以便可能调用以前的 mixin 可能是:

.color("first argument", 200, 160);
.color(-42, 200, 160);
.color(3, 200, 160); // 3 doesn't need to be processed in the loop

换句话说,.loop应该从第二个开始检查 mixin 的所有参数,并对第一个参数应用不同的过程。所以我需要把mixin的骨架改成这样:

.color(...) {
   ...; // Handling the first parameter
   .loop (@arguments); // Handling the rest of the parameters
}

但是在您的解决方案中,变量@arguments包含整个参数列表,包括第一个。如何在不播放的情况下将其从列表中排除isnumber()

我准确地说,实际上在我的项目中,从第二个开始的每个参数都被处理,因此:

.loop(@list, @index: 1, @shade: NULL) when not (isnumber(@list)) and (isnumber(extract(@list, @index))) {
   .loop(@list, (@index + 1), extract(@list, @index));
}

变成

.loop(@list, @index: 1, @shade: NULL) when not (isnumber(@list)) and (isnumber(extract(@list, @index))) {
   .loop(@shade);
   .loop(@list, (@index + 1), extract(@list, @index));
}

而且这个过程不包括简单地改变一个固定的背景颜色<div>;)但我想简化我的问题。

非常感谢您的回答和宝贵的建议!


再次编辑:马丁,您向我推荐的内容非常有效。再次感谢 !

4

1 回答 1

2

Less 与你的第二个和第三个 mixin 混淆了.color,因为它们都可以只接受一个参数,如果@rest作为参数传递给 mixin 并且不是数字(即列表或空),它会导致更多问题。此外@rest......使用多个具有相同名称的 mixin 也很棘手 - 最好将参数传递给另一组 mixin(作为单个参数的列表),然后使用守卫或它们可以采用的参数数量在它们之间切换。

我会对 mixin 的结构有所不同(并添加一个 helper mixin .loop,根据传递给的内容进行循环.color)。

然后这两个 mixin 将像这样工作:

  • .color: 将所有参数传递@arguments给 mixin 中的单个参数.loop
    • .loop: 如果参数既不是列表也不是数值 -> 没有输出
    • .loop: 如果一个列表中有多个参数 -> 循环遍历列表直到你到达最后一个数值(或者当它遇到第一个非数字参数时停止)
    • .loop:到达最后一个参数时,根据其值返回输出
    • .loop: 如果参数是单个值 -> 根据单个参数返回输出

这可以这样做:

.loop(@list, @index: 1, @shade: NULL) when not (isnumber(@list)) and not (isnumber(extract(@list, @index))) and not (isnumber(@shade)) {}

.loop(@list, @index: 1, @shade: NULL) when not (isnumber(@list)) and (isnumber(extract(@list, @index))) {
   .loop(@list, (@index + 1), extract(@list, @index));
}

.loop(@list, @index: 1, @shade) when not (isnumber(@list)) and not (isnumber(extract(@list, @index))) {
    .loop(@shade);
}

.loop(@shade) when (isnumber(@shade)){
    #id {
        background-color: rgb(@shade, @shade, @shade);
    }
}

.color (...) {
    .loop(@arguments);
}

如果你现在打电话是这样的:

.color(120,160);

输出CSS将如下所示:

#id {
  background-color: #a0a0a0;
}

对应于最后一个参数的值 ->rgb(160,160,160)

现在只有列表中最后一个参数的输出。如果你想为每个参数做一些事情,你可以在第二个.loopmixin(实际循环)中这样做,并且可以去掉第三个,它只用于将最后一个迭代步骤与循环的其余部分分开。


编辑:

对于您的附加问题“如何以不同的方式处理某些参数以及当它们不是数字时该怎么办? ” - >一般答案:您始终可以调整警卫,并为特定情况添加额外的混合。

例如,如果您想使用 不同地对待第一个参数(或任何参数).loop,您可以添加一个额外的.loopmixin - 像这样:

.loop(@list) when not (isnumber(@list)) {
   /* do something with the first argument */
   @first_argument: extract(@list, 1);
   /* start the loop at the second argument:*/
   .loop(@list, 2);
}

其余部分保持原样,这应该可以满足您的要求:

  • 将您的"first argument"from the保存@arguments到变量中(或者您可以随心所欲地使用它)
  • 从第二个参数开始循环并继续直到它到达最后一个数字参数(如上所示)

如前所述,这只是说明如何按照您的要求进行操作的示例……但是您必须使用它并根据您想要的结果和您的具体问题设计守卫和混合。

在循环中,你可以对每个参数做一些事情......你可以对数字和非数字参数做不同的事情(你只需要调整守卫中的条件),你还可以检查参数是否有特定的单位等等. 所有这一切都很简单,因为您只是使用extract()函数迭代列表并增加@index变量。

如果第一个参数/前几个参数有一个特定的赋值,你可以@rest像我展示的那样使用@arguments,并.color在你发送@rest.loop. 你会做这样的事情:

.color (@first, @rest...) {
   /* do something with the first argument */
   @first_argument: @first;
   /* send the rest to the loop */
   .loop(@rest);
}
于 2013-08-09T23:32:16.467 回答