HAML. Сборник рецептов
Развивая тему использования полюбившегося мне и моим коллегам инструмента для верстки, я предлагаю вам еще одну заметку о HAML. Ниже будут примеры кода, часть которых выдернута из контекста повседневных задач, другие навеяны вопросами, полученными мною по материалам предыдущих заметок. Так или иначе, все примеры должны оказаться полезными и вы без труда найдете им применение.
- Передача массива в подключаемый файл
- Многострочный JavaScript
- Сброс кэширования файла стилей и скриптов
- Пользовательские функции
- Многострочные массивы
- Получение элемента массива по индексу
- Массивы с внутренним счетчиком
- Псевдослучайные числа
Передача массива в подключаемый файл
Передачу переменной в подключаемый файл я уже рассматривал ранее и, казалось бы, о том, как это будет выглядеть в случае с массивом можно просто догадаться. Но обилие полученных мною вопросов говорит о поспешности сделанных выводов.
Передача массива выглядит следующим образом:
= Haml::Engine.new(File.read('./inc/file.haml')).render(parent, :add_scripts => ['./assets/js/somescript.min.js', 'http://example.com/someone.js'])
Подключаемый файл file.haml содержит следующий код:
- add_scripts.each do |script|
%script{src: "#{script}"}
В принципе, этого достаточно для решения задачи, но если возможна ситуация, когда файл file.haml может подключаться без передачи переменной add_scripts, получим ошибку компиляции, говорящую о том, что переменная add_scripts не существует. Решение очень простое — проверять существование переменной и выполнять цикл только в том случае, если она объявлена.
- if defined? add_scripts
- add_scripts.each do |script|
%script{src: "#{script}"}
Многострочный JavaScript
Для корректного включения в тело HTML документа JavaScript кода необходимо использовать фильтр :javascript
:javascript
jQuery(function($) {
});
Такой код не только компилируется в нормальный многострочный javascript, но и сохраняет полноценную подсветку синтаксиса в IDE (не во всех, безусловно, но IDEA и её младшие браться-сестры справляются).
Есть и другие фильтры, но мы им применения не нашли (не было необходимости), поэтому, кроме нескольких, отдельно упоминать их не стану, а кому интересно, найдут их в официальной документации.
Сброс кэширования файла стилей и скриптов
Если вы показываете клиенту промежуточные результаты верстки, уверен, приходилось слышать комментарии о том, что с предыдущей демонстрации ничего не изменилось или страничка «поехала». Причина, как правило, одна — у клиента попали в кэш подключаемые файлы стилей и скриптов. Чтобы избавить себя от подобных вопросов, в пути подключения всех внешних ресурсов мы добавили динамический параметр. Прием существует столько, сколько существует Интернет, но при использовании HAML он очень удобен и позволяет навсегда забыть о необходимости контролировать ситуацию.
- add_scripts.each do |script|
%script{src: "#{script}?#{Time.now.strftime("%m%d%y%M%S")}"}
В html мы получим примерно следующее:
<script src="./assets/js/somescript.min.js?0917155512"></script>
<script src="http://example.com/someone.js?0917155512"></script>
Пользовательские функции
Выше я уже описывал один из доступных фильтров. В работе мы используем еще один, позволяющий создавать свои функции и вызывать их в дальнейшем точно также, как и встроенные.
Если быть точным, то данный фильтр позволяет не просто создавать функции, а встраивать Ruby код в haml файл. Все, что будет «отфильтровано» с помощью фильтра :ruby, парсится с помощью Ruby интерпретатора и выполняется в том же контексте, что и haml код. Это значит, что созданная в фильтре, например, переменная будет доступна в любом месте шаблона (ниже после инициализации).
Пример функции, с помощью которой мы вставляем иконки от Fontawesome.
:ruby
def fa_icon(name)
html = '<i class="fa fa-' + name + '"></i>'
return html
end
= fa_icon('bomb');
Вызов fa_icon('bomb')
дает ожидаемый результат:
<i class="fa fa-bomb"></i>
Многострочные массивы
В целом, это еще один пример использования фильтра :ruby, суть которого раскрыта выше. Но так как мне задавали вопросы именно по созданию многострочных массивов, вынес его отдельным пунктом.
Имея в своем распоряжении всю мощь руби, мы можем создавать не только многострочные массивы, с которыми банально удобнее работать, но и массивы объектов, например.
:ruby
sidebar_menu = [
{'id' => 'search', 'icon' => 'icon-magnifier', 'text' => 'Search', 'url' => 'search'},
{'id' => 'device', 'icon' => 'icon-drawer', 'text' => 'Device', 'url' => 'device'},
{'id' => 'profiles', 'icon' => 'icon-book-open', 'text' => 'Profiles', 'url' => 'profiles'},
{'id' => 'settings', 'icon' => 'icon-book-open', 'text' => 'Settings', 'url' => 'settings'}
]
- sidebar_menu.each do |item|
%li
%a{href: "./#{item['url']}.html"}
%i{class: "#{item['icon']}"}
#{item['text']}
Получим следующий html:
<li>
<a href="./search.html">
<i class="icon-magnifier"></i>
Search
</a>
</li>
<li>
<a href="./device.html">
<i class="icon-drawer"></i>
Device
</a>
</li>
<li>
<a href="./profiles.html">
<i class="icon-book-open"></i>
Profiles
</a>
</li>
<li>
<a href="./settings.html">
<i class="icon-book-open"></i>
Settings
</a>
</li>
Получение элемента массива по индексу
Верстка — не программирование, конечно, и необходимость работать с элементами массива по индексу встречается нечасто. Тем не менее, иногда необходимо получить последний элемент массива. Для этого можно обратить к нему по индексу -1.
- colors = ['007896', '777361', '418f29', '35b890', 'ed3220', 'ffc700', 'ffffff', '0741ab', '0b0b0b']
= colors[-1] # выведет 0b0b0b
= colors[2] # выведет 418f29
Массивы с внутренним счетчиком
Внутренний счетчик — индекс элемента массива на текущей итерации цикла. Позволяет не создавать дополнительных переменных для отслеживания индекса текущего элемента. Удобно использовать совместно с условными операторами при формировании сеток элементов нужного размера.
- (0...5).each_with_index do |item, index|
= index
-# выведет 0 1 2 3 4
Используя свойство size объекта массива мы получим количество элементов в массиве. В сочетании с внутренним индексом это позволяет определить последнюю итерацию цикла при обходе массива.
- array = ['cat', 'dog', 'fly', 'mouse'];
- array.each_with_index do |item, index|
- if index == array.size-1
last element is "#{item}"
Псевдослучайные числа
Крайне удобная возможность, в сочетании с массивами, позволяющая решать множество задач, встречающихся при верстке. Для генерации псевдослучайного числа используется функция rand(), принимающая в качестве параметра целое число, определяющее максимальное значение псевдослучайного числа или Range. Также может быть вызвана без параметра, что равно вызову rand(0).
= rand() # вернет число вида 0.2769118273184681
= rand(0..10) # вернет число из диапазона от 0 до 10 включительно
= rand(0...10) # вернет число из диапазона от 0 до 9
Где применять? Например, необходимо вывести набор checkbox’ов, где у каждого будет свой label, активирующий checkbox.
- ['007896', '777361', '418f29', '35b890', 'ed3220', 'ffc700', 'ffffff', '0741ab', '0b0b0b'].each do |item|
- input_id = rand(1..99999)
%input.filter-checkbox{type: 'checkbox', id: "filter_id_#{input_id}"}/
%label.label-checkbox{for: "filter_id_#{input_id}", style: "background-color: \##{item}"} ##{item}
Здесь мы имеем массив с набором цветов в шестнадцатеричном формате. Каждому должен соответствовать один checkbox и связанный с ним label. Сохранение вызова rand() в переменную input_id позволяет создать уникальные ID для чекбоксов и использовать их в параметре for тэга label.
- (1..12).each do |item|
- image_id = rand(1..3)
.product
%a{href: '#'}
%img.product-image{src: "./placeholders/b-catalog-grid-image-#{image_id}.jpg", width: 227, height: 289, alt: ''}/
По коду видно, что имена подключаемых изображений отличаются лишь индексом, который мы определяем псевдослучайным числом из диапазона от 1 до 3 включительно. Такая сетка будет смотреться более привлекательно.
Заключение
Пожалуй, это все основные приемы, встречающиеся в нашей повседневной работе. Комбинирование этих приемов позволяет существенно экономить время, которое тратится на верстку средних и крупных проектов. На небольших задачах, вероятно, эффект будет не таким заметным, но мы настолько привыкли к HAML, что верстать непосредственно HTML код уже давно не пробуем, чего и вам советую :)