Pull to refresh

Туториал по Jade для начинающих

Reading time 8 min
Views 227K
Original author: Sanjay Guruprasad


Jade — это препроцессор HTML и шаблонизатор, который был написан на JavaScript для Node.js. Проще говоря, Jade — это именно то средство, которое предоставляет вам возможность написания разметки совершенно по новому, с целым рядом преимуществ по сравнению с обычным HTML.
К примеру, взгляните на код ниже в формате HTML:
<div>
  <h1>Ocean's Eleven</h1>
  <ul>
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
  <p>Danny Ocean and his eleven accomplices plan to rob
     three Las Vegas casinos simultaneously.</p>
</div>

А так эта разметка выглядит в формате Jade:
div
  h1 Ocean's Eleven
  ul
    li Comedy
    li Thriller
  p.
    Danny Ocean and his eleven accomplices plan to rob
    three Las Vegas casinos simultaneously.

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

Основы


Я собираюсь выделить три основные черты Jade:
  • Простые теги;
  • Добавление атрибутов в теги;
  • Блоки текста.

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

Теги

Как вы могли заметить ранее, в Jade нет закрывающих тегов. Вместо этого Jade использует табуляцию для определения вложености тегов.
div
  p Hello!
  p World!

В приведенном выше примере, теги параграфов согласно их табуляции при компиляции в конечном итоге окажутся внутри тега div. Как просто!
<div>
  <p>Hello!</p>
  <p>World!</p>
</div>

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

Посмотреть этот пример на CodePen

Атрибуты

Всё это, конечно, хорошо, но как добавлять атрибуты нашим тегам? На самом деле довольно просто.
Давайте вернёмся к нашему первому примеру и добавим туда пару классов и некую картинку-постер.
div(class="movie-card", id="oceans-11")
  h1(class="movie-title") Ocean's 11
  img(src="/img/oceans-11.png", class="movie-poster")
  ul(class="genre-list")
    li Comedy
    li Thriller

Как чудестно, не так ли?
<div class="movie-card" id="oceans-11">
  <h1 class="movie-title">Ocean's 11</h1>
  <img src="/img/oceans-11.png" class="movie-poster">
  <ul class="genre-list">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>


Посмотреть этот пример на CodePen

Но зачем останавливаться на достигнутом?! Jade предоставляет специальную стенографию для индификаторов и классов, что ещё больше упрощает нашу разметку, используя знакомые всем обозначения:
div.movie-card#oceans-11
  h1.movie-title Ocean's 11
  img.movie-poster(src="/img/oceans-11.png")
  ul.genre-list
    li Comedy
    li Thriller


Посмотреть этот пример на CodePen

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

Блоки текста

Давайте представим такую ситуацию: у вас есть тег <р> и вы хотите добавить в него довольно таки большой объём текста. Но стоп, ведь Jade рассматривает первое слово каждой строки как новый HTML-тег — и как тут быть?

В самом первом примере вы уже могли заметить невзрачную точку после тега параграфа. Добавление точки после вашего тега даёт понять компилятору Jade, что всё внутри данного тега является текстом.
div
  p How are you?
  p.
    I'm fine thank you.
    And you? I heard you fell into a lake?
    That's rather unfortunate. I hate it when my shoes get wet.


Посмотреть этот пример на CodePen

Для полной ясности: в случае, если я не поставил бы точку после тега <р> в примере, то скомпилированный HTML имел бы в себе открытый тег <і>, разорвав словосочетание “I’m” в начале строки.

Полезные функции


Теперь, когда мы разобрались с основами, давайте рассмотрим некоторые в действительности полезные функции, которые сделают нашу разметку умнее. Среди них:
  • JavaScript;
  • Циклы;
  • Интерполирование;
  • Миксины.


JavaScript в Jade

Jade реализован на JavaScript, по этому использовать JavaScript в Jade довольно просто. Вот пример:
- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li Hello
    - }

Что же мы тут сделали?! Начав строку с дефиса, мы указали компилятору Jade, что мыхотим использовать JavaScript, и всё, оно работает! И вот что мы получим, когда скомпилируем этот код в HTML:
<div>
  <ul>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
  </ul>
</div>


Посмотреть этот пример на CodePen

Мы используем дефис, когда код не должен напрямую попадать в поток вывода. В случае, ежели мы хотим использовать JavaScript для вывода чего-либо в Jade, мы используем =. Давайте подправим код выше, чтобы указать нумерацию элементов в списке:
- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li= i + ". Hello"
    - }

И вуаля, у нас имеется нумерация:
<div>
  <ul>
    <li>1. Hello</li>
    <li>2. Hello</li>
    <li>3. Hello</li>
    <li>4. Hello</li>
    <li>5. Hello</li>
  </ul>
</div>


Посмотреть этот пример на CodePen

Конечно, в данном случае нумерованный список был бы гораздо уместнее, но идею то вы уловили? Для более детальной информации ознакомтесь с документацией.

Циклы

Jade использует прекрасный синтаксис для написания циклов, так что вам не придётся прибегать к JavaScript. Давайте пройдёмся по элементам массива в цикле:
- var droids = ["R2D2", "C3PO", "BB8"];
div
  h1 Famous Droids from Star Wars
  for name in droids
    div.card
      h2= name

И это будет скомпилировано следующим образом:
<div>
  <h1>Famous Droids from Star Wars</h1>
  <div class="card">
    <h2>R2D2</h2>
  </div>
  <div class="card">
    <h2>C3PO</h2>
  </div>
  <div class="card">
    <h2>BB8</h2>
  </div>
</div>


Посмотреть этот пример на CodePen

Вы можете перемещаться по объектам массива, а также исспользовать цикл while. Узнайте больше прочитав документацию.

Интерполирование

Совмещать текст и JavaScript таким образом
p= «Hi there, » + profileName + ". How are you doing?"
может начать мусолить вам глаз. Разве Jade не имеет более элегантного решения данной задачи? Поспорим?
- var profileName = "Danny Ocean";
div
  p Hi there, #{profileName}. How are you doing?


Посмотреть этот пример на CodePen

Разве так не аккуратней?

Миксины

Миксины, они как функции, они принимают параметры в качестве входных данных и генерируют соответствующию разметку. Миксины оглашаются с помощью ключевого слова mixin.
mixin thumbnail(imageName, caption)
  div.thumbnail
    img(src="/img/#{imageName}.jpg")
    h4.image-caption= caption

После того, как миксин был оглашён, вы можете его вызвать с помощью символа +.
+thumbnail("oceans-eleven", "Danny Ocean makes an elevator pitch.")
+thumbnail("pirates", "Introducing Captain Jack Sparrow!")

Что будет скомпилировано как:
<div class="thumbnail">
  <img src="/img/oceans-eleven.jpg">
  <h4 class="image-caption">
    Danny Ocean makes an elevator pitch.
  </h4>
</div>
<div class="thumbnail">
  <img src="/img/pirates.jpg">
  <h4 class="image-caption">
    Introducing Captain Jack Sparrow!
  </h4>
</div>


Собираем все вместе


Давайте соберём всё, что мы успели выучить, в один пример. Скажем, у нас есть массив фильмов, каждый объект которого содержит название фильма, актёрский состав (под-массив), рейтинг, жанр, ссылку на IMDB-страницу и путь к картинке (которая будет использована в качестве постера фильма). Массив будет иметь примерно такой выгляд:
- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 7
  }
  // etc...
];

У нас есть 10 фильмов и мы хотим сделать симпатичную разметку для каждого из них. Изначально, мы не предусмотрели использование ссылки на IMDB-страницу фильма. Если рейтинг фильма выше 5, мы даём ему иконку с поднятым большим пальцем руки вверх, в ином случае, большой палец — вниз. Мы используем все выше перечисленные полезные функции Jade для написания данного модульного кода, который выполнит следующие задачи:

  1. Создать миксин под названием movie-card
    • Перебрать массив и вывести актёрский состав.
    • Перебрать массив и вывести жанры.
    • Проверить рейтинг фильма и присвоить ему соответсвующею иконку.

  2. Пребрать массив фильмов и использовать миксин для создания разметки.


И так, создадим миксин:
mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
      each actor in movie.cast
        li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

В данном коде много чего происходит, но я уверен, что он вам понятен, так как мы это уже прошли. Теперь, всё, что нам нужно, — это вызвать данный миксин в цикле:
for movie in movieList
  +movie-card(movie)

И всё! Разве это не классно?! Вот окончательный код:
- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 9.2
  },
  {
    title: "Pirates of the Caribbean",
    cast: ["Johnny Depp", "Keira Knightley", "Orlando Bloom"],
    genres: ["Adventure", "Comedy"],
    posterImage: "/img/pirates-caribbean",
    imdbURL: "http://www.imdb.com/title/tt0325980/",
    rating: 9.7
  }
];

mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

for movie in movieList
  +movie-card(movie)

А так код будет выглядеть после компиляции:
<div class="movie-card">
  <h2 class="movie-title">Ocean's Eleven</h2>
    <img src="/img/oceans-eleven" class="movie-poster"/>
  <h3>Cast</h3>
  <ul class="cast">
    <li>Julia Roberts</li>
    <li>George Clooney</li>
    <li>Brad Pitt</li>
    <li>Andy Garcia</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up"/>
  </div>
  <ul class="genre">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>
<div class="movie-card">
  <h2 class="movie-title">Pirates of the Carribean</h2>
  <img src="/img/pirates-caribbean" class="movie-poster"/>
  <h3>Cast</h3>
  <ul class="cast">
    <li>Johnny Depp</li>
    <li>Keira Knightley</li>
    <li>Orlando Bloom</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up"/>
  </div>
  <ul class="genre">
    <li>Adventure</li>
    <li>Comedy</li>
  </ul>
</div>

Но стоп, погодите минутку! А что, если теперь нам нужна возвожность переходить на IMDB-страницу фильма при нажатии на его название? Нам всего лишь потребуется добавить одну строку
a(href=movie.imdbURL)
в наш миксин.
mixin movie-card(movie)
  div.movie-card
    a(href=movie.imdbURL)
      h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre


Посмотреть этот пример на CodePen

Вывод


Сегодня мы с вами прошли путь от полного незнания препроцессора Jade к написанию, с его помощью, прекрасной модульной разметки. Это не всё, что может Jade, но я надеюсь, что данная статья задела ваше любопытство, и вы захотели узнать больше.

Важное примечание: как некоторые из вас, возможно, уже знают, Jade был переименован в Pug. В будущем, статьи о Jade будут использовать новое название «Pug» или «Pug.js».
Tags:
Hubs:
+20
Comments 74
Comments Comments 74

Articles