【问题标题】:Building a variadic mixin in LESS在 LESS 中构建可变参数 mixin
【发布时间】:2013-08-13 16:58:17
【问题描述】:

我正在尝试在 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 应该检查整个参数列表,并使用与 mixin 的最后一个参数对应的灰色阴影(在本例中为 rgb(160, 160, 160))。

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

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

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

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


编辑

This 完美运行,非常感谢!

但是我想问另一个问题。假设我的 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> 的背景颜色;)但我想简化我的问题。

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


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

【问题讨论】:

    标签: css less


    【解决方案1】:

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

    我会稍微不同地构建 mixin(并添加一个辅助 mixin .loop,它根据传递给 .color 的内容进行循环)。

    这两个 mixin 会像这样工作:

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

    Less可以这样做:

    .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)

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


    编辑:

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

    例如,如果您想使用 .loop 以不同方式处理第一个参数(或任何参数),您可以添加一个额外的 .loop 混合 - 像这样:

    .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"@arguments 保存到变量中(或者您可以随心所欲地使用它)
    • 从第二个参数开始循环并继续直到它到达最后一个数字参数(如上所示)

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

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

    如果第一个参数/前几个参数有一个特定的分配,你可以使用@rest,就像我用@arguments展示的一样,并在你之前对.color mixin中的第一个参数做一些事情将@rest 发送到.loop。你会做这样的事情:

    .color (@first, @rest...) {
       /* do something with the first argument */
       @first_argument: @first;
       /* send the rest to the loop */
       .loop(@rest);
    }
    

    【讨论】:

    • 我想评论你的答案,但我的帖子太长了,所以我回答了我自己的问题。谢谢!
    • 按照您的要求,我更新了我的问题。您在编辑的消息中建议的更改非常有效。非常感谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 2014-10-08
    相关资源
    最近更新 更多