Шаблоны

3

На данный момент переведено

В этой главе вы:

  • Узнаете о языке шаблонов Meteor, Spacebars.
  • Создадите свои первые 3 шаблона.
  • Узнаете как работают менеджеры Meteor.
  • Основы статического прототипирования.
  • Чтобы облегчить разработку в Meteor, мы будем применять outside-in подход. Другими словами, в начале мы создадим обычный HTML/JavaScript шаблон, а затем подключим его к нашему приложению.

    Это означает, что в этой главе мы коснемся только того, что происходит в директории /client.

    Создадим новый файл main.html в директории /client и добавим в файл следующий код:

    <head>
      <title>Microscope</title>
    </head>
    <body>
      <div class="container">
        <header class="navbar navbar-default" role="navigation"> 
          <div class="navbar-header">
            <a class="navbar-brand" href="/">Microscope</a>
          </div>
        </header>
        <div id="main" class="row-fluid">
          {{> postsList}}
        </div>
      </div>
    </body>
    
    client/main.html

    Это будет наш главный шаблон приложения. Как вы заметили, это обычный HTML, кроме тега {{> postsList}}. Он является точкой входа шаблона postsList, который мы создадим позже. Теперь создадим еще пару шаблонов.

    Шаблоны в Meteor

    По своей сути, социально-новостной сайт состоит из сообщений, организованных в виде списка, именно так мы организуем наши шаблоны.

    Теперь создадим директорию /views внутри /client. Туда мы положим все наши шаблоны. Также создадим директорию /posts внутри /views. Там будут находится шаблоны, которые связаны с новостями.

    Поиск файлов

    Meteor силен в поиске файлов. Не имеет значения, куда мы положили код внутри директории /client, Meteor найдет его и обработает должным образом. Это означает, что нет необходимости вручную прописывать пути к JavaScript и CSS файлам.

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

    Итак, создадим наш второй шаблон. В директории client/views/posts, создадим файл posts_list.html со следующим содержанием:

    <template name="postsList">
      <div class="posts">
        {{#each posts}}
          {{> postItem}}
        {{/each}}
      </div>
    </template>
    
    client/views/posts/posts_list.html

    Также создадим файл post_item.html со следующим содержанием:

    <template name="postItem">
      <div class="post">
        <div class="post-content">
          <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
        </div>
      </div>
    </template>
    
    client/views/posts/post_item.html

    Обратите внимание на атрибут name="postsList" тега <template> . Это имя используется для того, чтобы Meteor понимал, какой и где шаблон используется. В этом случае шаблон будет внутри основного (его мы создали ранее), вместо тега {{> postsList}}.

    Настало время освоить шаблонизатор, который используется в Meteor - Handlebars. Handlebars это простой HTML с добавлением трех вещей: partials, expressions и block helpers.

    Partials - это конструкция вида {{> имяШаблона}}, с помощью которой мы обращаемся к Meteor и сообщаем ему, чтобы он заменил ее шаблоном с тем же именем (в нашем случае это postItem).

    Expressions, такие как {{title}}, или вызывают свойство текущего объекта, или же возвращают значение, которое определено в текущем менеджере шаблонов (подробнее об этом позже).

    Block helpers - это специальные теги, такие как {{#each}}…{{/each}} или {{#if}}…{{/if}}, с помощью которых можно создавать логические конструкции прямо в шаблоне.

    Едем дальше

    Вы можете зайти на официальный сайт Handlebars или на этот удобный учебник если хотите узнать больше о Handlebars.

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

    Во-первых, шаблон postsList мы выводим в цикле с помощью конструкции {{#each}}…{{/each}}. Для каждой итерации мы подключаем шаблон postItem.

    Так откуда берется объект posts? Хороший вопрос. На самом деле это template helper, мы определим его позже, после того, как посмотрим на template managers.

    Шаблон postItem довольно прост. Он использует только три выражения: {{url}} и {{title}}, которые возвращают свойства документа, и {{domain}}, который вызывает template helper.

    Мы уже не раз упоминали выражение “template helpers” в этой главе, не объясняя, что он делает. Но для того, чтобы исправить это, мы должны сначала поговорить о менеджерах.

    Template Managers (менеджеры шаблонов)

    До сих пор мы имели дело с Handlebars, который является обычным HTML с дополнительными тегами. В отличие от других языков, таких как PHP (или даже обычных HTML страниц, которые могут содержать JavaScript), Meteor разделяет шаблоны от логики, и эти шаблоны ничего не делают сами по себе.

    Для того, чтобы вдохнуть жизнь в шаблон, нам нужен manager. Вы можете думать о менеджере как о поваре, который получает сырье (ваши данные) и готовит их, прежде чем передать готовое блюдо официанту (шаблону), который принесет его вам.

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

    Менеджеры?

    Когда мы спросили у разработчиков Meteor, что они подразумевают под фразой template managers, то кто-то из них сказал, что это контроллеры, а кто-то сказал: “Это те файлы, куда я положил свой JavaScript код”.

    Менеджеры на самом деле не являются контроллерами (по крайней мере, не в смысле контроллеров в MVC) и “Те файлы, куда я положил свой JavaScript код” тоже не является истиной, поэтому мы отклонили оба ответа.

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

    Для простоты, мы будем называть файлы менеджеров шаблонов как и сами шаблоны, за исключением их расширения .js. Итак, создадим файл posts_list.js в директории /client/views/posts прямо сейчас и начнем создание нашего первого менеджера:

    var postsData = [
      {
        title: 'Introducing Telescope',
        url: 'http://sachagreif.com/introducing-telescope/'
      }, 
      {
        title: 'Meteor',
        url: 'http://meteor.com'
      }, 
      {
        title: 'The Meteor Book',
        url: 'http://themeteorbook.com'
      }
    ];
    Template.postsList.helpers({
      posts: postsData
    });
    
    client/views/posts/posts_list.js

    Если вы все сделали правильно, теперь вы должны видеть что-то похожее в вашем браузере:

    Our first templates with static data
    Our first templates with static data

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

    Во-вторых, мы используем функцию Template.myTemplate.helpers() для определения шаблона хелпера posts, который просто возвращает наш массив postsData.

    Определение хелпера posts означает, что он теперь доступен для использования в нашем шаблоне:

    <template name="postsList">
      <div class="posts">
        {{#each posts}}
          {{> postItem}}
        {{/each}}
      </div>
    </template>
    
    client/views/posts/posts_list.html

    Таким образом, наш шаблон может перебирать массив postsData и подставлять каждый элемента массива в цикле вместо тега postItem в шаблоне.

    Коммит 3-1

    Added basic posts list template and static data.

    Хелпер domain

    Теперь создадим менеджер post_item.js, в котором будет храниться логика шаблона postItem:

    Template.postItem.helpers({
      domain: function() {
        var a = document.createElement('a');
        a.href = this.url;
        return a.hostname;
      }
    });
    
    client/views/posts/post_item.js

    На этот раз наш хелпер domain является не массивом, а анонимной функцией. Этот паттерн является более распространенным (и более полезным) по сравнению с нашим предыдущим примером, где мы использовали массив вместо базы данных.

    Displaying domains for each links.
    Displaying domains for each links.

    Хелпер domain берет URL и возвращает домен, используя немного магии JavaScript. Но где же брать url?

    Ответ на вопрос мы можем найти, вернувшись немного назад, к файлу шаблона posts_list.html. Блок {{#each}} не только перебирает наш массив, а еще и устанавливает значение this внутри блока.

    Это означает, что между тэгами {{#each}}, каждый пост во время итерации обозначается как this, и это распространяется на все пути, которые подключены внутри менеджера (post_item.js).

    Теперь мы понимаем, почему this.url возвращает текущий URL поста (элемента массива postsData). Более того, если мы используем {{title}} и {{url}} внутри нашего шаблона post_item.html, Meteor понимает, что мы имеем в виду, написав this.title и this.url, и возвращает нам корректные значения.

    Коммит 3-2

    Setup a `domain` helper on the `postItem`.

    Магия JavaScript

    Хотя это не является специфичным для Meteor, но вот краткое объяснение того, что происходило выше: это всего лишь немного “магии JavaScript”. Во-первых, мы создаем пустой элемент HTML (a) и храним его в памяти.

    Затем мы устанавливаем ему атрибут href, равный нашему URL (как вы заметили ранее, он является объектом хелпера и вызывается через this).

    Наконец, мы воспользуемся свойством hostname элемента a, чтобы получить ссылку только на домен, без остальной части URL.

    Если вы сделали все без ошибок, то вы должны увидеть в браузере список сообщений. Этот список является всего лишь статическими данными. Мы пока не используем все прекрасные возможности real-time, которые предоставляет нам Meteor. Мы покажем вам, как использовать эти возможности в следующей главе!

    Горячее обновление кода

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

    Это потому что Meteor отслеживает все файлы в директории проекта и автоматически обновляет страницу, если обнаружит изменения в каком-либо файле.

    Горячее обновление кода в Meteor устроено довольно умно, и может даже сохранять состояние вашего приложения между двумя обновлениями!