Работа с переменными и примесями
Чтобы компилятор выполнял хоть сколько-нибудь полезные действия, интерпретируя 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 вы загрязняете его и усложняете для восприятия.