【问题标题】:Passing a variable from inside a mixin declaration into the attached content block?将mixin声明中的变量传递到附加的内容块中?
【发布时间】:2012-12-12 19:17:03
【问题描述】:

在 Ruby 中,您可以轻松地将方法内部的变量传递到附加的代码块中:

def mymethod
  (1..10).each { |e| yield(e * 10) } # Passes a number to associated block
end

mymethod { |i| puts "Here comes #{i}" } # Outputs the number received from the method

我想在 SASS mixin 中做同样的事情:

=my-mixin
  @for $i from 1 to 8
    .grid-#{$i}
      @content

+my-mixin
  color: nth("red green blue orange yellow brown black purple", $i)

此代码不起作用,因为 $i 是在 mixin 声明中声明的,并且在使用 mixin 的外部无法看到。 :(

那么...我如何利用在 mixin 声明中声明的变量?

当我使用网格框架和媒体查询时,我非常需要这个功能。目前我每次需要时都必须复制 mixin 声明中的内容,这违反了 DRY 规则。

UPD 2013-01-24

这是一个真实的例子。

我有一个 mixin 循环遍历断点并为每个断点应用一次提供的代码:

=apply-to-each-bp
  @each $bp in $bp-list
    +at-breakpoint($bp) // This is from Susy gem
      @content

当我使用这个 mixin 时,我必须在 @content 中使用这个 $bp 值。可能是这样的:

// Applies to all direct children of container
.container > *
  display: inline-block

// Applies to all direct children of container,
// if container does not have the .with-gutters class
.container:not(.with-gutters) > *
  +apply-to-each-bp
    width: 100% / $bp

// Applies to all direct children of container,
// if container has the .with-gutters class
.container.with-gutters  > *
  +apply-to-each-bp
    $block-to-margin-ratio: 0.2
    $width: 100% / ($bp * (1 + $block-to-margin-ratio) - $block-to-margin-ratio)
    width: $width
    margin-right: $width * $block-to-margin-ratio

    &:nth-child(#{$bp})
      margin-right: 0

但这行不通,因为 $bp 的值在 @content 中不可用。

在调用 mixin 之前声明变量不会有帮助,因为 @content 在 mixin 被解析之前被解析一次。

相反,每次我需要它时,我都必须做两条丑陋的大腿:

  1. 声明一个 ad-hoc mixin,
  2. 写循环,违反DRY原则:
// Each of the following mixins is mentioned in the code only once.
=without-gutters($bp)
  width: 100% / $bp

=with-gutters($bp)
  $block-to-margin-ratio: 0.2
  $width: 100% / ($bp * (1 + $block-to-margin-ratio) - $block-to-margin-ratio)
  width: $width
  margin-right: $width * $block-to-margin-ratio

  &:nth-child(#{$bp})
    margin-right: 0

// Applies to all direct children of container
.container > *
  display: inline-block

// Applies to all direct children of container,
// if container does not have the .with-gutters class
.container:not(.with-gutters) > *
  @each $bp in $bp-list
    +at-breakpoint($bp) // This is from Susy gem
      +without-gutters($bp)

// Applies to all direct children of container,
// if container has the .with-gutters class
.container.with-gutters  > *
  @each $bp in $bp-list  // Duplicate code! :(
    +at-breakpoint($bp)  // Violates the DRY principle.
      +with-gutters($bp)

所以,问题是:有没有办法做到这种 Ruby 风格?

【问题讨论】:

    标签: compass-sass sass susy-compass


    【解决方案1】:

    所以这目前在 Sass 中不可用。

    在 Sass 问题队列中有一张相关的票:https://github.com/nex3/sass/issues/871 它处于计划状态,但至少要到 Sass 4.0 才能实现。

    【讨论】:

      【解决方案2】:

      我自己也遇到过这个问题,AFAIK 这是目前 SASS 的一个限制。

      【讨论】:

        【解决方案3】:

        Sass 中的变量具有作用域。它们仅在创建它们的块中可见。如果您希望变量在 mixin 内部和外部都可以访问,则必须在全局范围内定义它:

        $var: 0;
        
        @mixin test {
            $var: $var + 1;
            color: red;
        }
        
        .test {
            $var: 5;
            @include test;
            @debug $var; // DEBUG: 6
        }
        

        只要您不关心$var 的状态很长时间,这应该可以满足您的目的。

        对于您的示例,这不起作用,因为它看起来像 @content 被首先处理。你需要的是一个以不同方式编写的 mixin:

        @mixin test($properties...) {
            @for $i from 1 to 8 {
                .grid-#{$i} {
                    @each $p in $properties {
                        $list: nth($p, 2);
                        @if length($list) > 1 {
                            #{nth($p, 1)}: nth($list, $i);
                        } @else {
                            #{nth($p, 1)}: $list;
                        }
                    }
                    @content;
                }
            }
        }
        
        .test {
            @include test(color (red green blue orange yellow brown black purple));
        }
        

        生成的 CSS:

        .test .grid-1 {
          color: red;
        }
        
        .test .grid-2 {
          color: green;
        }
        
        .test .grid-3 {
          color: blue;
        }
        
        .test .grid-4 {
          color: orange;
        }
        
        .test .grid-5 {
          color: yellow;
        }
        
        .test .grid-6 {
          color: brown;
        }
        
        .test .grid-7 {
          color: black;
        }
        

        像这样的 mixin 可以输入任意数量的参数,如果你愿意,仍然可以使用 @content

        【讨论】:

        • 亲爱的cimmanon,您建议的解决方案不适用于这种情况。我已经编辑了我最初的问题,以添加一个我正在寻找的彻底且几乎真实的示例。请查看并写下您的考虑。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-14
        相关资源
        最近更新 更多