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

Циклы HTML: Препроцессор Pug

В уроке про условные конструкции был использован объект с данными пользователя Кодовёнка Хекслетовича:

const user = {
  name: 'Кодовёнок',
  surname: 'Хекслетович',
  login: 'hexlet-code',
}

При обращении к полям объекта использовалась схема объект.ключ. Таким способом были получены данные об имени, фамилии и логине пользователя:

-
  const user = {
    name: 'Кодовёнок',
    surname: 'Хекслетович',
    login: 'hexlet-code',
  }

section.user-profile
  p.name
    if user.name && user.surname
      | #{user.name} #{user.surname}
    else
      | #{user.login}

Преобразуем немного задачу и выведем пользователя в рейтинге обучающихся. Добавим количество баллов и все данные в таблицу:

-
  const user = {
    name: 'Кодовёнок',
    surname: 'Хекслетович',
    login: 'hexlet-code',
    scores: 1271
  }

section.container
  h2 Рейтинг пользователей

  table
    thead
      tr
        th Имя
        th Фамилия
        th Логин
        th Баллы
    tbody
      tr
        td= user.name
        td= user.surname
        td= user.login
        td= user.scores

Задача легко решается, если необходимо вывести одного пользователя. А что же делать, если пользователя 2? 3? 100? Есть два способа:

  1. Плохой: записать каждого пользователя в свою переменную и методом «копировать-вставить» добавить всех пользователей.
  2. Хороший: создать массив users, внутри которого будут все пользователи. Таким образом каждому пользователю будет выделено своё место в массиве, а значит можно удобно добавлять или удалять пользователей.

Создадим массив users и добавим туда несколько разных пользователей:

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

Для обхода такого массива используются специальные конструкции — циклы. Их задача — пройтись по каждому элементу массива и получить информацию внутри него. Проходы по элементам называется итерацией. Во время первой итерации будут получены данные Кодовёнка Хекслетовича. Во время второй итерации данные Короля Вёрстки.

Основным типом цикла в Pug считается цикл each in. Буквально его можно читать как для каждого «a» внутри «b». Где:

  • «a» — произвольное имя переменной, которая будет доступна во время итерации.
  • «b» — массив или объект, из которого необходимо получить данные.
-
  const users = [
    {
      name: 'Кодовёнок',
      surname: 'Хекслетович',
      login: 'hexlet-code',
      scores: 1271
    },
    {
      name: 'Король',
      surname: 'Вёрстки',
      login: 'king-of-layout',
      scores: 1100
    },
  ]

section.container
  h2 Рейтинг пользователей

  table
    thead
      tr
        th Имя
        th Фамилия
        th Логин
        th Баллы
    tbody
      each user in users
        tr
          td= user.name
          td= user.surname
          td= user.login
          td= user.scores
<section class="container">
  <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>
</section>

Главное изменение произошло добавлением всего одной строки: each user in users. Запись читается следующим образом: для каждого user в массиве users и далее вывод табличной строки с данными.


Важно: вы можете присвоить любое имя переменной, которая будет доступна внутри цикла. В прошлом примере таким именем может быть не user, а people или как-то иначе. Только вы выбираете это имя, но старайтесь называть его так, чтобы было понятно, что кроется за этим названием. Если код внутри цикла большой, то именно от именования зависит то, как быстро и точно будет интерпретирован код вами или другим разработчиком.

Подробнее можно почитать в статьях:


Нельзя точно быть уверенным, что массив, по которому будет происходить перебор имеет хоть один элемент. Если нет ни одного элемента, то всё, что внутри массива не будет выведено. В этот момент пользователю важно знать, что информации нет, а не возникла ошибка на странице. Для этого можно использовать конструкцию each else. Это схоже с условной конструкцией, но срабатывает только при пустом массиве.

- const users = []

section.container
  h2 Рейтинг пользователей

  table
    thead
      tr
        th Имя
        th Фамилия
        th Логин
        th Баллы
    tbody
      each user in users
        tr
          td= user.name
          td= user.surname
          td= user.login
          td= user.scores
      else
        tr
          td(colspan='4') Нет пользователей
<section class="container">
  <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>

Код из прошлого примера эквивалентен следующей записи:

- const users = []

if users.length
  each user in users
    tr
      td= user.name
      td= user.surname
      td= user.login
      td= user.scores
else
  tr
    td(colspan='4') Нет пользователей

Вложенные циклы и получение ключа объекта

При переборе объекта бывает необходимо получить не только значение, но и ключ, по которому располагается объект. Например, пользователи могут делиться на разные группы: пользователи, модераторы, администраторы. В таком случае объект может иметь следующий вид:

const users = {
  admin: [
    {
      name: 'Кодовёнок',
      surname: 'Хекслетович',
    },
  ],
  moderator: [
    {
      name: 'Король',
      surname: 'Вёрстки',
    },
    {
      name: 'Алексей',
      surname: 'Примадонин',
    },
  ],
}

Объект users имеет несколько ключей: admin и moderator, значением которых являются массивы пользователей. Для вывода такого списка вместе с указанием должности используется немного изменённый синтаксис цикла each. В нём необходимо получить имя ключа и массив.

each people, position in users
  h2= position
  ul
    each user in people
      li= user.name + ' ' + user.surname

Из объекта users принимаются несколько данных: в переменную people попадает значение, а в переменную position ключ. Обратите внимание на порядок переменных — вначале данные, а потом ключ.

В этом примере используется вложенный цикл. Такая практика является стандартным для обхода больших данных. При первой итерации в верхнем цикле вытаскиваются следующие данные:

const people = [
  {
    name: 'Кодовёнок',
    surname: 'Хекслетович',
  },
];

const position = 'admin';

В дальнейшем идёт перебор по массиву people, которое происходит так же, как и в примере выше.

<h2>admin</h2>
<ul>
  <li>Кодовёнок Хекслетович</li>
</ul>
<h2>moderator</h2>
<ul>
  <li>Король Вёрстки</li>
  <li>Алексей Примадонин</li>
</ul>

Цикл while

Цикл each по праву считается основным при работе с Pug, но он не является единственным. Встречаются ситуации, когда необходимо несколько раз повторить одни и те же действия. В этом случае each никак не поможет, но в Pug существует ещё один тип цикла — while. Его задача — повторение участка кода пока истинно условие. Например,

- let count = 0;

ul
  while count < 5
    li= "Hello, my number is " + count
    - count += 1;
<ul>
  <li>Hello, my number is 0</li>
  <li>Hello, my number is 1</li>
  <li>Hello, my number is 2</li>
  <li>Hello, my number is 3</li>
  <li>Hello, my number is 4</li>
</ul>

При использовании цикла while важно следить за тем, чтобы условие рано или поздно преобразовалось в ложь. Это частая ошибка, которая может привести к бесконечному циклу. В пришлом примере для получения бесконечного цикла достаточно опустить строку count += 1;. Без неё значение переменной count всегда будет равно нулю, а значит условие count < 5 будет истинным в любой момент времени компиляции.

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

В файл icon.pug попадает массив следующего вида:

-
  const icons = {
    free: [
      {
        name: 'robot',
        url: './icons/robot.svg'
      },
      {
        name: 'hexlet',
        url: './icons/hexlet.svg'
      }
    ],
    premium: [
      {
        name: 'cat',
        url: './icons/premium/cat.svg'
      },
      {
        name: 'dog',
        url: './icons/premium/dog.svg'
      }
    ]
  };

Преобразуйте данные в шаблон следующего вида:

<h2>free</h2>
<ul>
  <li><a href="./icons/robot.svg">robot</a></li>
  <li><a href="./icons/hexlet.svg">hexlet</a></li>
</ul>
<h2>premium</h2>
<ul>
  <li><a href="./icons/premium/cat.svg">cat</a></li>
  <li><a href="./icons/premium/dog.svg">dog</a></li>
</ul>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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