Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Миксины HTML: Препроцессор Pug

При разработке сайта количество одинаковых по структуре блоков велико. Представьте каталог интернет-магазина. Он может состоять из сотен карточек, которые отличаются только данными. При разработке «по старинке», без шаблонизаторов, все эти карточки верстаются методом «копировать-вставить». Не идеальное решение, но вполне рабочее. Именно так кажется до тех пор, пока не произойдёт изменение карточек. Любое добавление/удаление элементов приведёт к часам, а то и дням работы по изменению вёрстки.

Это кажется невероятным, но похожие ситуации встречаются не настолько редко, как может показаться. Поэтому разработчику важно научиться работать с повторяющимися участками кода.

Для переиспользования вёрстки в Pug используются миксины — конструкция, позволяющая описать и подставлять код в любую часть вёрстки. Это отличное решение для создания компонентов.

В качестве примера используем компонент кнопки. Это несложная конструкция, которая может состоять всего из одного тега. Для создания миксина используется ключевое слово mixin, после чего идёт произвольное имя миксина. Это имя вы выбираете сами, при этом не забывайте о грамотном именовании. Внутрь миксина помещается весь HTML, который будет нужен. В данном случае один тег <button>:

mixin buttonOrder
  button.btn.btn-order Оформить заявку

Вот и всё. Простая конструкция, но с множеством возможностей, о которых поговорим чуть ниже. Сейчас необходимо вызвать этот миксин, чтобы его тело попало в итоговый HTML-код. Здесь важно понимать, что сам миксин никак не попадает в итоговую разметку. Для вызова миксина указывается символ + и название миксина. После этого он подставится в HTML-код.

mixin buttonOrder
  button.btn.btn-order Оформить заявку

+buttonOrder
<button class="btn btn-order">Оформить заявку</button>

Каждый миксин может быть вызван неограниченное количество раз:

mixin buttonOrder
  button.btn.btn-order Оформить заявку

+buttonOrder
+buttonOrder
+buttonOrder
<button class="btn btn-order">Оформить заявку</button>
<button class="btn btn-order">Оформить заявку</button>
<button class="btn btn-order">Оформить заявку</button>

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

Если нужна обёртка для логического компонента, то используется mixin, если нужно подключить шаблон в конкретный Pug-файл, то используется конструкция include.

Миксины как функции

В Pug миксины выполняют роль не только подстановщиков HTML-кода, но и функций, которые возвращают HTML. Отличительная черта таких миксинов — наличие аргументов, которые используются при вызове миксина. Вернёмся к системе кнопок из прошлого примера. На страницах приложения часто бывает несколько различных видов кнопок. Они могут различаться текстом, классами и так далее.

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

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

mixin button(title)
  button.btn.btn-order= title

Вызов таких миксинов осуществляется следующим образом:

mixin button(title)
  button.btn.btn-order= title

+button('Заказать')
<button class="btn btn-order">Заказать</button>

Миксины могут принимать и значения по умолчанию. Это полезно в случае, когда большинство элементов имеют одинаковый контент. Достаточно присвоить нужное значение в определении миксина:

mixin button(title = 'Заказать')
  button.btn.btn-order= title

+button
+button('Оформить заявку')
<button class="btn btn-order">Заказать</button>
<button class="btn btn-order">Оформить заявку</button>

Если используется дефолтное значение аргумента, то нет необходимости добавлять пустые круглые скобки при вызове, как это происходит в Sass.

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

-
  const users = [
    {
      name: 'Кодовёнок',
      surname: 'Хекслетович',
      login: 'hexlet-code',
      score: 1271
    },
    {
      name: 'Король',
      surname: 'Вёрстки',
      login: 'king-of-layout',
      score: 1100
    },
  ]

mixin createUserTable(usersData = [])
  table
    thead
      tr
        th Имя
        th Фамилия
        th Логин
        th Баллы
    tbody
      each user in usersData
        tr
          td= user.name
          td= user.surname
          td= user.login
          td= user.score
      else
        tr
          td(colspan='4') Пользователи отсутствуют

section
  h2 Лучшие из лучших
  +createUserTable(users)

  h2 Худшие из худших
  +createUserTable(badUsers)

Единожды создав миксин, у вас появилась возможность использовать его с абсолютно разными данными, которые придут в Pug. Можно пойти ещё дальше и проверять поля, типы значений, валидировать и нормализовать данные. В качестве значения по умолчанию был указан пустой массив. Это гарантирует, что если данные отсутствуют или переменная не существует, то будет подставлен пустой массив.


<section>
  <h2>Лучшие из лучших</h2>
  <table>
    <thead>
      <tr>
        <th>Имя</th>
        <th>Фамилия</th>
        <th>Логин</th>
        <th>Баллы</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Кодовёнок</td>
        <td>Хекслетович</td>
        <td>hexlet-code</td>
        <td>1271</td>
      </tr>
      <tr>
        <td>Король</td>
        <td>Вёрстки</td>
        <td>king-of-layout</td>
        <td>1100</td>
      </tr>
    </tbody>
  </table>

  <h2>Худшие из худших</h2>
  <table>
    <thead>
      <tr>
        <th>Имя</th>
        <th>Фамилия</th>
        <th>Логин</th>
        <th>Баллы</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td colspan="4">Пользователи отсутствуют</td>
      </tr>
    </tbody>
  </table>
</section>

Передача вложенного контента в миксин

Миксины могут использоваться в виде «скелета» структуры компонента. Это может быть оформление статьи, которая выводится на странице в виде следующего шаблона:

<article class="post">
  <h2>Название статьи</h2>

  <div class="post-body">
    <p>Текст статьи</p>
  </div>

  <div class="post-author">
    <p>Автор статьи</p>
  </div>
</article>

Если таких статей много на сайте, то есть смысл вынести шаблон в отдельный миксин. Но как же передать данные? Тут есть два пути:

  1. Определить аргументы, и передавать их отдельно в миксин.
  2. Каким-то образом сразу передать всю статью.

Первый способ может быть неудобен из-за тела статьи. Ведь статья не является произведением из одного предложения, которое можно передать в виде аргумента миксина. К тому же статьи зачастую хранятся в отдельном файле, как было в уроке про include. Поэтому лучшим вариантом в данной ситуации может считаться передача текста непосредственно в миксин с использованием вложенности. Вызовем миксин article, передав в качестве аргументов название и автора статьи, а в тело поместив подключение файла.

+article('Название статьи', 'Автор статьи')
  include:markdown-it main.md

Главный вопрос: а куда подставится результат выполнения include:markdown-it main.md. На самом деле никуда! Миксин не знает, что делать с этими данными, хотя и может их принять. Для подстановки вложенных в миксин данных используется конструкция block, в которой и хранится то, что было вложено в миксин. Можно считать это «невидимым аргументом», который всегда есть, но не объявляется явно. Теперь можно реализовать логику миксина:

mixin article(name, author)
  .post
    h2= name

    .post-body
      block

    .post-author= author

+article('Название статьи', 'Автор статьи')
  include:markdown-it main.md
<div class="post">
  <h2>Название статьи</h2>
  <div class="post-body">
    <p>Текст статьи из файла main.md</p>
  </div>
  <div class="post-author">Автор статьи</div>
</div>

Дополнительное задание

Доработайте миксин с добавлением статьи на страницу:

  1. Проверьте, что существует контент для отображения. Если его нет, то выведите ошибку.
  2. Добавьте значения по умолчанию для аргументов. В качестве имени статьи используйте «Hexlet». В качестве автора «Кодовёнок»

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
900
упражнения
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Изображение Тото

Задавайте вопросы, если хотите обсудить теорию или упражнения. Команда поддержки Хекслета и опытные участники сообщества помогут найти ответы и решить задачу