将一个变量从mixin声明中传递到附加的内容块中?

时间:2012-12-27 11:33:44

标签: compass-sass sass susy-compass

在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原则:
  3. // 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风格?

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

我自己遇到了这个问题而AFAIK这是SASS的当前限制。

答案 2 :(得分:1)

所以这在Sass目前无法使用。

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