Працюючи над складними архітектурами Sass, нерідко використовується карта Sass для підтримки конфігурації та опцій. Час від часу на картах (можливо, на декількох рівнях) ви бачите такі карти, як ця з 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 );
Проблема таких карт полягає в тому, що отримати та встановити значення з вкладеного дерева непросто. Це, безумовно, щось, що ви хочете приховати в межах функцій, щоб уникнути необхідності робити це кожен раз вручну.
Глибоко отримати
Насправді, побудувати функцію для отримання глибоко вкладених значень з карти дуже просто.
/// 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; )
Наприклад, якщо ми хочемо отримати значення, пов'язане з M
макетом, з нашої конфігураційної карти, це так просто, як:
$m-breakpoint: map-deep-get($o-grid-default-config, "layouts", "M"); // 610px
Зверніть увагу, що лапки навколо рядків необов’язкові. Ми додаємо їх лише для забезпечення читабельності.
Глибокий набір
З іншого боку, побудова функції для встановлення глибоко вкладеного ключа може бути дуже нудною.
/// 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; )
Тепер, якщо ми хочемо оновити значення, пов'язане з M
макетом, з нашої конфігураційної карти, ми можемо зробити:
$o-grid-default-config: map-deep-set($o-grid-default-config, "layouts" "M", 650px);
Додаткові ресурси
Вищевказана функція не є єдиним рішенням цієї проблеми.
Бібліотека Sassy-Maps також надає map-deep-set
та map-deep-get
функціонує. У тому ж напрямку, Уго Жиродель також написав extend
функцію стилю jQuery, щоб зробити вбудовану map-merge
рекурсивну та здатною об'єднати більше 2 карт одночасно.