【问题标题】:How do I get particular anonymous argument in LESS mixin如何在 LESS mixin 中获得特定的匿名参数
【发布时间】:2013-03-28 11:37:19
【问题描述】:

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

我有一个 LESS 混合器

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

【问题讨论】:

    标签: arguments less mixins


    【解决方案1】:

    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(不过仍然是一个好问题),同时还可以访问单个值。

    .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%);
    }
    

    【讨论】:

    • 嗯,我希望我可以编写一个立即执行的 javascript 函数来做类似的事情。因为这似乎正是我所需要的。
    • 据我所知,没有办法编写单个 javascript 函数来产生您想要的 LESS 输出。当然,我不是 javascript 专家(我可以应付,但不是天才),所以我可能是错的。
    • 一切皆有可能,相信我。
    • 我还添加了自己的答案,因为我现在已经解决了我的问题。我在 1.4 发布之前或在 Web Essentials Visual Studio 插件更新之前为所有需要它的人发布了它。我在最后一组。但我会赞成你的回答,因为它也很有帮助。在不久的将来。
    【解决方案2】:

    关于此解决方案的详细博文可以发送至 found here

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

    是否可以从 @arguments 访问单个参数而不使用字符串转换?

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

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

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

    .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%"]
    

    现在我们有了可以使用的数据。由于也无法提供不是 color 对象的 LESS mix 参数,因此我们必须手动进行混合。

    这是.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}")
    

    【讨论】:

    • +1 用于为 LESS 的早期版本寻找答案并将所有内容放在一个函数中。
    • 您应该着眼于帮助LESS group 解决其颜色函数的问题,以便真正可以传递字符串并返回可用于其他颜色函数的有效颜色。这样做会简化这一点并解决您的其他问题。
    • 会的。这是对color 函数的一个相当简单的更改,以使其与#xxx#xxxxxxrgbrgba 字符串一起使用。我不确定是否包含像hsl 这样的其他人是否有意义,但前四个将使它成为更好的体验。也许我应该分叉它并提出拉取请求。 :)
    猜你喜欢
    • 2017-01-19
    • 2012-08-13
    • 1970-01-01
    • 2014-10-08
    • 2014-10-15
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2014-10-03
    相关资源
    最近更新 更多