【问题标题】:Using LESS mixin to set variable multiple times but getting wrong results使用 LESS mixin 多次设置变量但得到错误结果
【发布时间】:2014-03-23 06:20:59
【问题描述】:

在前面,我今天开始少了……

欢迎提出如何更好地做到这一点的任何建议!

我有以下 .less 文件:

.test(@target;@context) {
  @em: (@target / @context) * 1em;
}

.custom-field {
  position: relative;
  .test(30;16);
  padding-bottom: @em;
  .test(30;16);
  margin-bottom: @em;
  .test(320;16);
  max-width: @em;
}

我希望 padding-bottom 和 margin-bottom 的值为 1.875 和 max-width: 20。

但这就是输出:

.custom-field {
  position: relative;
  padding-bottom: 1.875em;
  margin-bottom: 1.875em;
  max-width: 1.875em;
}

我在开始时将第二个参数作为可选参数。但是为了测试,我让它尽可能简单。

如果我更频繁地使用 mixin,我会得到更多奇怪的结果。至少对我来说,它们很奇怪:)

有人给我建议吗?

【问题讨论】:

    标签: less mixins


    【解决方案1】:

    LESS variables "lazy load",这意味着它们在代码中出现的顺序无关紧要,通常是“最后”调用获胜。在您的情况下,我发现奇怪的是,我本以为它们都是20em,因为这是该值的“最后”设置。但是,我从发布this "issue" 中了解到,这特别是因为它被mixin 调用,它是唯一设置的第一个值。由于延迟加载,它会影响调用变量的整个作用域,并且因为无论调用多少次,mixin 都只会设置一次值,你最终会得到看起来像“奇怪”的行为。

    你至少有四种方法可以处理你的情况,它们会输出你想要的。

    (1) 在 Mixin 中设置属性

    .test(@target;@context;@prop) {
      @{prop}: (@target / @context) * 1em;
    }
    
    .custom-field {
      position: relative;
      .test(30;16;padding-bottom);
      .test(30;16;margin-bottom);
      .test(320;16;max-width);
    }
    

    (2) 设置全局Javascript函数

    仔细注意它是如何构建/使用的。在您对 SASS 发表评论后,我从 this thread 那里得到了这个想法。可以通过这种方式设置各种功能。

    @setEm: `setEm = function(target,context) { return ((target/context)+'em'); }`;
    
    .custom-field {
      position: relative;
      padding-bottom: ~`setEm(30,16)`;
      margin-bottom: ~`setEm(30,16)`;
      max-width: ~`setEm(320,16)`;
    }
    

    (3) 使用模式匹配的非 Javascript 解决方案

    仔细注意它是如何构造/使用的。这更“冗长”,但确实避免了对 javascript 环境的调用(如果需要,或者他们有时会删除内联 javascript 功能 [which has been discussed during various issues on the site]) 并提供了一些很好的灵活性。也可以使用它来设置各种功能(如图所示)。

    /*make a global setter for local variable getter (this will get up to six  
    /*values from the same caller function to avoid variable overlap; should you 
    /*need more within a single scope block, just expand this).
    */
    
    .setGetInstance(@num) {
      .-(@num);
      .-(1) { @getVar1: @setVar;}
      .-(2) { @getVar2: @setVar;}
      .-(3) { @getVar3: @setVar;}
      .-(4) { @getVar4: @setVar;}
      .-(5) { @getVar5: @setVar;}
      .-(6) { @getVar6: @setVar;}
    }
    
    /*Create various "function" mixins that use the global setter */
    
    .setEm(@target;@context;@num) {
      @setVar: ((@target / @context) * 1em);
      .setGetInstance(@num);
    }
    .-100(@target;@num) {
      @setVar: (@target - 100px);
      .setGetInstance(@num);
    } 
    
    /*Use the function mixins (up to six per block in this example) */
    
    .custom-field1 {
      position: relative;
      .setEm(30;16;1;);
      padding-bottom: @getVar1;
      .setEm(30;16;2);
      margin-bottom: @getVar2;
      .setEm(320;16;3);
      max-width: @getVar3;
    }
    .custom-field2 {
      .setEm(20;10;1;);
      padding-bottom: @getVar1;
      .setEm(10;10;2);
      margin-bottom: @getVar2;
      .minus100(1000;3);
      max-width: @getVar3;
    }
    

    CSS 输出

    .custom-field1 {
      position: relative;
      padding-bottom: 1.875em;
      margin-bottom: 1.875em;
      max-width: 20em;
    }
    .custom-field2 {
      padding-bottom: 2em;
      margin-bottom: 1em;
      max-width: 900px;
    }
    

    (4) 使用嵌套块或 Mixins

    我从this comment 学到了另一种方法,它也以不同的方式解决了这个问题。

    .setEm(@target;@context) {
      @em: ((@target / @context) * 1em);
    }
    
    .custom-field {
      position: relative;
      & {padding-bottom: @em; .setEm(30;16);}
      & {margin-bottom: @em; .setEm(30;16);}
      & {max-width: @em; .setEm(320;16);}
    }
    

    但是,这将在 1.6.2 之前的任何版本的 LESS 中产生多个选择器块,就像这样(1.6.2+ 将它们全部合并,请参阅 7-phases-max 的评论):

    .custom-field {
      position: relative;
    }
    .custom-field {
      padding-bottom: 1.875em;
    }
    .custom-field {
      margin-bottom: 1.875em;
    }
    .custom-field {
      max-width: 20em;
    }
    

    因此,如果使用早期版本,最好将其保留为本地 mixin:

    .custom-field {
      position: relative;
      .-() {padding-bottom: @em; .setEm(30;16);}
      .-() {margin-bottom: @em; .setEm(30;16);}
      .-() {max-width: @em; .setEm(320;16);}
      .-() 
    }
    

    将所有内容分组:

    .custom-field {
      position: relative;
      padding-bottom: 1.875em;
      margin-bottom: 1.875em;
      max-width: 20em;
    }
    

    【讨论】:

    • 哦,谢谢!是的,如果我返回测试,我看到我得到了正确的值: (@target / @context) * 1em;期待您的第二个解决方案。
    • 我认为使用 sass 更容易,因为函数能力不是吗? @function em($target, $context) { @return ($target / $context) * 1em; }
    • 您对 SASS 的评论让我想起了上面添加的第二个解决方案。
    • 感谢您的帮助!我发现解决方案最适合我。也许我什至为此使用 SASS。对 CSS 预处理完全陌生。
    • 顺便说一句。 > (4) “这将产生多个选择器块” - 仅在 Less 1.6.2 之前,在此版本之后 & {} 块被合并到父规则集中,因此不再有 CSS 膨胀超出此类范围。
    猜你喜欢
    • 2012-03-18
    • 1970-01-01
    • 2013-08-27
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多