Bij het werken aan complexe Sass-architecturen is het niet ongebruikelijk om Sass-kaarten te gebruiken om de configuratie en opties te behouden. Van tijd tot tijd zie je kaarten binnen kaarten (mogelijk op verschillende niveaus) zoals deze van o-grid:
$o-grid-default-config: ( columns: 12, gutter: 10px, min-width: 240px, max-width: 1330px, layouts: ( S: 370px, // ≥20px columns M: 610px, // ≥40px columns L: 850px, // ≥60px columns XL: 1090px // ≥80px columns ), fluid: true, debug: false, fixed-layout: M, enhanced-experience: true );
Het probleem met dergelijke kaarten is dat het niet gemakkelijk is om waarden uit de geneste boom te krijgen en in te stellen. Dit is absoluut iets dat u binnen functies wilt verbergen om te voorkomen dat u het elke keer handmatig moet doen.
Diep krijgen
Eigenlijk is het bouwen van een functie om diep geneste waarden van een kaart op te halen heel eenvoudig.
/// Map deep get /// @author Hugo Giraudel /// @access public /// @param (Map) $map - Map /// @param (Arglist) $keys - Key chain /// @return (*) - Desired value @function map-deep-get($map, $keys… ) ( @each $key in $keys ( $map: map-get($map, $key); ) @return $map; )
Als we bijvoorbeeld de waarde die aan de M
lay-out is gekoppeld, uit onze configuratiekaart willen halen , is dat zo eenvoudig als:
$m-breakpoint: map-deep-get($o-grid-default-config, "layouts", "M"); // 610px
Merk op dat aanhalingstekens rond strings optioneel zijn. We voegen ze alleen toe om redenen van leesbaarheid.
Diepe set
Aan de andere kant kan het bouwen van een functie om een diep geneste sleutel in te stellen erg vervelend zijn.
/// Deep set function to set a value in nested maps /// @author Hugo Giraudel /// @access public /// @param (Map) $map - Map /// @param (List) $keys - Key chaine /// @param (*) $value - Value to assign /// @return (Map) @function map-deep-set($map, $keys, $value) ( $maps: ($map,); $result: null; // If the last key is a map already // Warn the user we will be overriding it with $value @if type-of(nth($keys, -1)) == "map" ( @warn "The last key you specified is a map; it will be overrided with `#($value)`."; ) // If $keys is a single key // Just merge and return @if length($keys) == 1 ( @return map-merge($map, ($keys: $value)); ) // Loop from the first to the second to last key from $keys // Store the associated map to this key in the $maps list // If the key doesn't exist, throw an error @for $i from 1 through length($keys) - 1 ( $current-key: nth($keys, $i); $current-map: nth($maps, -1); $current-get: map-get($current-map, $current-key); @if $current-get == null ( @error "Key `#($key)` doesn't exist at current level in map."; ) $maps: append($maps, $current-get); ) // Loop from the last map to the first one // Merge it with the previous one @for $i from length($maps) through 1 ( $current-map: nth($maps, $i); $current-key: nth($keys, $i); $current-val: if($i == length($maps), $value, $result); $result: map-merge($current-map, ($current-key: $current-val)); ) // Return result @return $result; )
Als we nu de waarde willen bijwerken die aan de M
lay-out is gekoppeld vanuit onze configuratiekaart, kunnen we het volgende doen:
$o-grid-default-config: map-deep-set($o-grid-default-config, "layouts" "M", 650px);
Extra middelen
De bovenstaande functie is niet de enige oplossing voor dit probleem.
De Sassy-Maps-bibliotheek biedt ook map-deep-set
en map-deep-get
functies. In dezelfde lijn heeft Hugo Giraudel ook een jQuery-achtige extend
functie geschreven om de ingebouwde map-merge
recursieve te maken en in staat te zijn om meer dan 2 kaarten tegelijk samen te voegen.