Работа с переменными и примесями

Чтобы компилятор выполнял хоть сколько-нибудь полезные действия, интерпретируя JavaScript-код — ему нужны значения, которые он может получить из переменных. Для того, чтобы получить значения переменных, необходимо использовать один из представленных ниже вариантов синтаксиса:

.test-js {
  @test: 123;
  content: `@{test}`;
  content: `this.test.toJS()`;
}

Оба варианта хорошо работают с локальными переменными. С глобальными переменными работает лишь первый способ, так как this, во втором случае, явно указывает на контекст, то есть селектор. Без контекста test.toJS() работать не будет.

Результатом компиляции будет:

.test-js {
  content: 123;
  content: "123";
}

Далее я приведу несколько примеров работы с переменными, используя JavaScript-код в Less:

.test-js {
  // Интерполяция
  @world: "world";
  content: ~`'hello' + ' ' + @{world}`;

  // Списки
  @list:  1, 2, 3;
  @list-js: ~`@{list}.join(', ')`;
  content: @list-js;
}

Компилятор создаст два свойства content и присвоит им вполне валидные значения:

.test-js {
  content: hello world;
  content: 1, 2, 3;
}

Первый пример демонстрирует возможность интерполяции строк прямиком в JavaScript, второй — работу со списками.

Немного подробнее остановимся на списках. Ранее я уже говорил, что списки — это альтернатива массивам в JavaScript. Списки в Less можно итерировать и узнавать их длину. Тот список, что определён в переменной @list никаких вопросов не вызывает:

.test-js {
  @list:  1, 2, 3;
  content: length(@list);
  content: extract(@list, 1);
}

// На выходе получаем
.test-js {
  content: 3; // Длина
  content: 1; // Первый элемент массива
}

А вот значение переменной @list-js списком не является, так как на выходе JavaScript-кода всегда находится строка:

.test-js {
  @list:  1, 2, 3;
  @list-js: ~`@{list}.join(', ')`;
  content: length(@list-js);
  content: extract(@list-js, 1);
}

// На выходе получаем
.test-js {
  content: 1;       // Длина
  content: 1, 2, 3; // Первый элемент массива
}

Примеси

Наиболее очевидным применением возможностей JavaScript-кода в Less является создание примесей, которые на вход получают какое-то количество переменных, обрабатывают их, используя JavaScript и возвращают строку, как результат.

Конечное число переменных

Самым простым способом получить значения из переменных в Less является следующая функция:

(function(a, b) {
  return a + b;
})('@{a}', '@{b}')

Используя обёртку в виде примеси, её можно представить в удобном для использования виде:

.mixin(@a, @b) {
  @js: ~`(function(a, b) { return a + b; })('@{a}', '@{b}')`;

  content: @js;
}

.test-js {
  .mixin(1, 2);
}

Результатом компиляции будет являться сумма двух чисел, переданных, как аргументы примеси .mixin():

.test-js {
  content: 12;
}

Неопределённое число переменных

Если для проведения операций в выражении требуется большое количество переменных, или их количество неизвестно заранее, то на помощь приходит следующая функция, возвращающая массив всех переданных аргументов:

(function(args) {
  return args;
})('@{arguments}')

Записывая эту функцию в переменную и используя примесь, у которой на вход подаётся переменное количество аргументов, получим следующий less-код:

.mixin(...) {
  @js: ~`(function(args){ return args; })('@{arguments}')`;

  content: @js;
}

.test-js {
  .mixin(3, 123);
}

И, как я уже сказал, после компиляции будет доступен массив всех переданных значений:

.test-js {
  content: [3, 123];
}

В Less с таким результатом сделать ничего не получится (мешают квадратные скобки), поэтому на практике лучше всего использовать следующую модификацию предложенной функции:

(function(args) {
  return args;
})((function() {
  var args = '@{arguments}';
  return args.replace(/^\[|\]$/g, '')
})())

Этот вариант записи удаляет квадратные скобки, используя метод replace(), при этом делая получаемый на выходе массив немного лучше:

.mixin(...) {
  @js: ~`function(args){return args}(function(){var args='@{arguments}';return args.replace(/^\[|\]$/g,'')}())`;

  content: @js;
}

.test-js {
  .mixin(3, 123);
}

К сожалению, как я и показывал ранее — массив преобразуется в строку, содержимое которой нельзя итерировать.

.test-js {
  content: 3, 123;
}

Преобразование значений

Конечно, на практике мало пользы от того, что вы можете получить, распарсить и отдать результат обратно — необходимо с ним как-то взаимодействовать.

В приведённом ниже примере последнему в списке значению добавляется единица измерения deg:

(function(args) {
  return args = args || '0, 0, 0, 0', args = args.replace(/,\s*\d+$/, function(args) {
    return args + 'deg'
  })
})((function() {
  var args = '@{arguments}';
  return args = args.replace(/^\[|\]$/g, '')
})())

В итоге примесь имеет вид:

.rotate3d(...) {
  @js: ~`(function(args) { return args = args || '0, 0, 0, 0', args = args.replace(/,\s*\d+$/, function(args) { return args + 'deg' }) })((function() { var args = '@{arguments}'; return args = args.replace(/^\[|\]$/g, '') })())`;

  transform: rotate3d(@js);
}

.test-js {
  .rotate3d(1, 0, 0, 50);
}

После компиляции получится отформатированное значение свойства transform:

.test-js {
  transform: rotate3d(1, 0, 0, 50deg);
}

Если вызвать эту же примесь без аргументов, то будет выводиться результат по умолчанию, то есть нули:

.test-js {
  transform: rotate3d(0, 0, 0, 0deg);
}

Описанные в этой главе примеры доступны под номерами 6.1.1 - 6.1.4 и работают только с компиляторами, написанными на JavaScript.

Выводы и мысли

Да, Less умеет интерпретировать JavaScript-код, записанный в переменной или в значении свойства, но получаемая от этого польза слишком мала и не покрывает потраченных на это усилий. Используя JavaScript в Less вы загрязняете его и усложняете для восприятия.

results matching ""

    No results matching ""