Lorsque vous travaillez sur des architectures Sass complexes, il n'est pas rare d'utiliser des cartes Sass pour maintenir la configuration et les options. De temps en temps, vous verrez des cartes dans des cartes (éventuellement à plusieurs niveaux) comme celle-ci de 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 );
Le problème avec de telles cartes est qu'il n'est pas facile d'obtenir et de définir des valeurs à partir de l'arborescence imbriquée. C'est certainement quelque chose que vous voulez cacher dans les fonctions afin d'éviter d'avoir à le faire manuellement à chaque fois.
Deep get
En fait, créer une fonction pour récupérer des valeurs profondément imbriquées dans une carte est très simple.
/// 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; )
Par exemple, si nous voulons obtenir la valeur associée à la M
mise en page à partir de notre carte de configuration, c'est aussi simple que:
$m-breakpoint: map-deep-get($o-grid-default-config, "layouts", "M"); // 610px
Notez que les guillemets autour des chaînes sont facultatifs. Nous les ajoutons uniquement pour des problèmes de lisibilité.
Ensemble profond
D'un autre côté, créer une fonction pour définir une clé profondément imbriquée peut être très fastidieux.
/// 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; )
Maintenant, si nous voulons mettre à jour la valeur associée à la M
mise en page à partir de notre carte de configuration, nous pouvons faire:
$o-grid-default-config: map-deep-set($o-grid-default-config, "layouts" "M", 650px);
Ressources supplémentaires
La fonction ci-dessus n'est pas la seule solution à ce problème.
La bibliothèque Sassy-Maps fournit également map-deep-set
et map-deep-get
fonctionne. Dans le même esprit, Hugo Giraudel a également écrit une extend
fonction de style jQuery pour rendre la fonction intégrée map-merge
récursive et capable de fusionner plus de 2 cartes à la fois.