如何在LESS mixin中获得特定的匿名参数

时间:2013-03-28 11:37:20

标签: arguments less mixins

  

注意 :我不想使用~"parameters"表示法提供参数,因为它不是用户友好的,开发人员总是要考虑到这一点。我正在使用this trick进行javascript评估,以正确的格式获取参数,可以在下面的mixin中看到。

我有一个轻松的混音

.gradient(...) {
    @def = ~`"@{arguments}".replace(/[\[\]]/g,"")`;

    background-color: mix(/* first and last argument color */)
    background-image: linear-gradient(to bottom, @def);
}

由于渐变可以有多个颜色停止定义,我将其定义为支持任意数量的参数。

现在。我想得到的只是第一个和最后一个参数的颜色定义。问题是这些可以通过不同的方式提供,一些简单的提取其他复杂的:

.gradient(#000, #fff); // easy
.gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%); // complicated

问题

  1. 是否可以从@arguments访问单个参数而无需求助于字符串转换?
  2. 如果必须进行字符串转换(如~'"@{arguments}"'),如何拆分单个参数以忽略括号内的逗号(上面的复杂示例将这些转换为rbga值)?

2 个答案:

答案 0 :(得分:2)

LESS 1.4.0解决方案

以下是一个解决方案,它需要LESS 1.4.0(截至本文撰写时目前处于测试阶段),因为它使用了新的extract()函数。它还假设颜色将始终是每个参数的值集合中的第一个值(我应该相信linear-gradient css的正确语法。

通过使用LESS 1.4.0的extract()函数,我们可以允许参数作为非字符串which alleviates the string to color conversion issue you were having in your other question that we discussed传递(但仍然是一个很好的问题),同时还可以访问单个值

<强> LESS

.gradient(...) {

  //setting up your argument definition string
  @def: ~`"@{arguments}".replace(/[\[\]]/g,"")`;

  //getting the number of arguments 
  //(weeding out nested commas in parenthesis to do it)
  @numStops: unit(`"@{arguments}".replace(/\([^)]*\)/g,"").split(',').length`);

  //extracting raw form of first and last arguments
  //which may be more than just a single color
  @rawFirst: extract(@arguments,1);
  @rawLast: extract(@arguments,@numStops);

  //mixins to recursively evaluate the raw arguments down to a color
  .setFirstColor(@color) when (isColor(@color)) {
     @FirstColor: @color;
  }
  .setFirstColor(@color) when not (isColor(@color)) {
     .setFirstColor(extract(@color,1));
  }
  .setLastColor(@color) when (isColor(@color)) {
     @LastColor: @color;
  }
  .setLastColor(@color) when not (isColor(@color)) {
     .setLastColor(extract(@color,1));
  }

  //call mixins to get the first & last color from first & last arguments
  .setFirstColor(@rawFirst);
  .setLastColor(@rawLast);

  //set your css using the extracted and formatted info
  background-color: mix(@FirstColor, @LastColor);
  background-image: linear-gradient(to bottom, @def);
}

.myClass1 {
  .gradient(#000, #fff); 
}

.myClass2 {
  .gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%); //complicated
}

CSS输出

.myClass1 {
  background-color: #808080;
  background-image: linear-gradient(to bottom, #000000, #ffffff);
}
.myClass2 {
  background-color: rgba(179, 179, 179, 0.7);
  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 25%, #cccccc 50%, rgba(255, 255, 255, 0.9) 80%);
}

答案 1 :(得分:1)

  

有关此解决方案的详细博文可以是 found here

回答我自己的问题并提供可行的解决方案

是否可以从 @arguments 访问个别参数而无需借助字符串转换?

如果没有LESS 1.4(目前处于测试阶段),似乎无法直接执行此操作并获得实际参数而无需借助字符串转换然后操纵它们。

如果必须进行字符串转换( ~'"@{arguments}"' ),如何拆分单个参数以忽略括号内的逗号(上面的复杂示例将这些转换为 rgba 值)?

答案是立即执行匿名函数,返回所需的结果。让我们从问题中举例说明:

.gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%);

在mixin @def中执行第一行后,会为此值指定:

@def: "rgba(0, 0, 0, 0.5) 25%, #ccc 50%, rgba(255, 255, 255, 0.9) 80%";

现在我们要做的就是替换那些不应该分割的逗号。这些是括号内的逗号。使用先行正则表达式很容易检测到这一点。因此,我们用半冒号替换这些逗号,然后拆分留下的逗号:

val.replace(/,\s+(?=[\d ,.]+\))/gi, ";").split(/,\s*/g)

这导致这个字符串数组或单个渐变参数

["rgba(0;0;0;0.5) 25%", "#ccc 50%", "rgba(255;255;255;0.9) 80%"]

现在我们有了可以使用的数据。因为也不可能提供不是mixcolor个对象的参数,我们必须手动进行混合。

这导致.gradient mixin输出#xxxxxx作为第一个和最后一个渐变颜色的结果:

.gradient (...) {
    @all: ~`"@{arguments}".replace(/[\[\]]/g,"")`;
    @mix: ~`(function(a){a=a.replace(/,\s+(?=[\d ,.]+\))/gi,";").split(/,\s*/g);var f=a[0].split(/\s+/g)[0];var l=a.pop().split(/\s+/g)[0];var c=function(c){var r=[];/rgb/i.test(c)&&c.replace(/[\d.]+/g,function(i){r.push(1*i);return"";});/#.{3}$/.test(c)&&c.replace(/[\da-f]/ig,function(i){r.push(parseInt(i+i,16));return"";});/#.{6}/.test(c)&&c.replace(/[\da-f]{2}/ig,function(i){r.push(parseInt(i,16));return"";});if(r.length)return r;return[100,0,0];};var p=function(v){return("0"+v.toString(16)).match(/.{2}$/)[0];};f=c(f);l=c(l);var r={r:((f.shift()+l.shift())/2)|0,g:((f.shift()+l.shift())/2)|0,b:((f.shift()+l.shift())/2)|0};return"#"+p(r.r)+p(r.g)+p(r.b);})("@{arguments}")`;
    background-color: @mix;
    background-image: -webkit-linear-gradient(top, @all);
    background-image: -moz-linear-gradient(top, @all);
    background-image: -o-linear-gradient(top, @all);
    background-image: linear-gradient(to bottom, @all);
}

我们当然可以进一步复杂化并计算所有渐变颜色的平均值,但根据我的需要,这已经足够了。以下是执行解析参数以及计算渐变中第一种颜色和最后一种颜色的混合技巧的函数,并在上部@mix变量中缩小:

(function(args) {
    args = args.replace(/,\s+(?=[\d ,.]+\))/gi, ";").split(/,\s*/g);
    var first = args[0].split(/\s+/g)[0];
    var last = args.pop().split(/\s+/g)[0];

    var calculateValues = function(color) {
        var result = [];
        /rgb/i.test(color) && color.replace(/[\d.]+/g, function(i) {
            result.push(1*i);
            return "";
        });
        /#.{3}$/.test(color) && color.replace(/[\da-f]/ig, function(i) {
            result.push(parseInt(i+i, 16));
            return "";
        });
        /#.{6}/.test(color) && color.replace(/[\da-f]{2}/ig, function(i) {
            result.push(parseInt(i, 16));
            return "";
        });
        if (result.length) return result;
        return [100,0,0];
    };

    var padZero = function(val) {
        return ("0" + val.toString(16)).match(/.{2}$/)[0];
    };

    first = calculateValues(first);
    last = calculateValues(last);

    var result = {
        r: ((first.shift() + last.shift()) / 2) | 0,
        g: ((first.shift() + last.shift()) / 2) | 0,
        b: ((first.shift() + last.shift()) / 2) | 0
    };
    return "#"+ padZero(result.r) + padZero(result.g) + padZero(result.b);
})("@{arguments}")