5

在 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 规则。

更新 2013-01-24

这是一个真实的例子。

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

=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. 声明一个临时混合,
  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 风格?

4

3 回答 3

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

于 2012-12-27T13:42:06.237 回答
1

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

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

于 2014-01-17T08:12:31.543 回答
1

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

于 2013-06-10T12:03:17.867 回答