2012-12-27 16 views
5

In Ruby, können Sie einfach eine Variable aus innerhalb einer Methode in den beigefügten Codeblock übergeben:Eine Variable innerhalb einer Mixin-Deklaration in den angehängten Inhaltsblock übergeben?

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 

Ich möchte die gleiche Sache in SASS mixin tun:

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

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

Dieser gewonnen Code Es funktioniert nicht, weil $ i innerhalb der Mixin-Deklaration deklariert ist und nicht im Freien zu sehen ist, wo das Mixin verwendet wird. :(

So ... Wie nutzen i Variablen innerhalb der mixin Deklaration deklariert?

Wenn ich mit einem Gitterrahmen und Medienabfragen arbeiten, ich brauche diese Funktionalität schlecht. Zur Zeit muss ich duplizieren, was innerhalb der ist jedes Mal, wenn ich es mixin Erklärung benötigen, die DRY-Regel zu verletzen.

UPD 2013-01-24

Hier ist ein Beispiel aus der Praxis.

ich habe eine mixi n, die Zyklen durch Haltepunkte und einmal den bereitgestellten Code gelten für jeden Unterbrechungspunkt:

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

Wenn ich diesen mixin ich diesen $ bp Wert innerhalb @content verwenden. Es könnte so aussehen:

// 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 

Aber das wird nicht funktionieren, weil der Wert von $ bp nicht verfügbar innerhalb @content ist.

Das Deklarieren der Variablen vor dem Aufruf des Mixins hilft nicht, weil @content einmal analysiert wird und bevor das Mixin geparst wird.

Stattdessen ich jedes Mal muß, dass, ich habe zwei hässliche Oberschenkel zu tun:

  1. einen Ad-hoc-mixin erklären,
  2. schreiben den Zyklus, Verstoß gegen das DRY-Prinzip:
// 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) 

Also, die Frage ist: gibt es eine Möglichkeit, diese Ruby-Stil zu tun?

Antwort

1

Dies ist derzeit in Sass nicht verfügbar.

Es gibt ein relevantes Ticket in der Sass-Ausgabewarteschlange: https://github.com/nex3/sass/issues/871 Es ist im geplanten Zustand, wird es aber wahrscheinlich erst ab Sass 4.0 schaffen.

4

Variablen in Sass haben Bereich zu ihnen. Sie sind nur sichtbar, in dem Block sie erstellt wurden Wenn Sie die Variable wollen zugänglich sein, sowohl innerhalb als auch außerhalb des mixin, hat es im globalen Bereich definiert werden.

$var: 0; 

@mixin test { 
    $var: $var + 1; 
    color: red; 
} 

.test { 
    $var: 5; 
    @include test; 
    @debug $var; // DEBUG: 6 
} 

Solange Sie den Zustand von $var für sehr lange nicht interessiert, sollte dies für Ihre Zwecke gut funktionieren.

Für Ihr Beispiel wird dies nicht funktionieren, weil es so aussieht, als ob die @content zuerst verarbeitet wird.Was Sie brauchen, ist ein mixin, die anders geschrieben:

@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)); 
} 

Das erzeugte 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; 
} 

A mixin wie diese können eine beliebige Anzahl von Argumenten zugeführt werden und immer noch erlaubt Ihnen @content zu verwenden, wenn Sie es wünschen.

+0

Sehr geehrter Cimmanon, die von Ihnen vorgeschlagene Lösung trifft nicht auf die Situation zu. Ich habe meine erste Frage bearbeitet, um ein gründliches und fast realistisches Beispiel dessen hinzuzufügen, wonach ich suche. Bitte werfen Sie einen Blick und schreiben Sie Ihre Überlegungen. –

1

Ich habe selbst auf dieses Problem gestoßen und AFAIK das ist eine aktuelle Beschränkung in SASS.