Статьи

Введение в руль

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


Есть две основные причины, по которым вы хотите создать шаблон для своего сайта. Прежде всего, создание шаблона поощряет вас отделять код на основе логики от реального представления, помогая вам придерживаться шаблона View / Controller. Во-вторых, шаблоны обеспечивают чистоту и удобство обслуживания вашего кода, что, в свою очередь, упрощает процесс обновления вашего сайта. Вы не создаете сайт с Handlebars. Вместо этого вы создаете руководящие принципы и структуры, которые определяют, как должен выглядеть сайт, не сосредотачиваясь на данных страницы. Давайте рассмотрим некоторые из основ.


Handlebars генерирует ваш HTML, беря структуру JSON и пропуская ее через шаблон. Эти шаблоны написаны в основном в обычном HTML, и заполнены заполнителями, которые позволяют вводить данные по мере необходимости. Например, следующий шаблон приветствует пользователя при входе в систему:

1
<h1>Welcome back, {{name}}</h1>

Атрибут {{name}} — это место, где имя пользователя будет введено на страницу. Этот заполнитель соответствует свойству в структуре JSON данных. Это самый простой возможный пример, но вскоре вы увидите, что все остальное в основном сводится к этой простой концепции. Давайте перейдем к обработке массивов.

Handlebars поставляется с некоторыми встроенными помощниками, которые помогут вам в работе с более сложными данными. Один из этих помощников — each помощник. Этот помощник перебирает массив и позволяет вам создавать динамический HTML для каждого элемента массива. Например, следующий шаблон отображает данные массива, который содержит список локальных концертов, играющих в моей области:

01
02
03
04
05
06
07
08
09
10
<table>
    <tr>
        <th>Local Concerts</th>
    </tr>
    {{#each Concerts}}
        <tr>
            <td>{{this}}</td>
        </tr>
    {{/each}}
</table>

Как вы можете видеть, этот код намного чище, чем обычный код, такой как использование цикла в PHP или JavaScript для добавления HTML к переменной. Рули не навязчивы, и это делает Рули такими доступными. Вы также можете заметить, что мы используем имя атрибута this для извлечения текущего элемента массива в each цикле.

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<table>
    <tr>
        <th>Band Name</th>
        <th>Date</th>
        <th>Album Name</th>
    </tr>
    {{#each Bands}}
        <tr>
            <td>{{Name}}</td>
            <td>{{Date}}</td>
            <td>{{Albums.0.Name}}</td>
        </tr>
    {{/each}}
</table>

Вы можете сохранить свой шаблон в элементе <script /> и загрузить его с помощью JavaScript.

В Handlebars вы даже можете получить доступ к вложенным свойствам, как в примере выше ( Albums.0.Name ), и, конечно, вы могли бы использовать еще each цикл для перебора альбомов группы. Стоит отметить, что помимо точечной нотации для доступа к вложенным свойствам, вы также можете использовать «../» для доступа к родительским свойствам.

Что делать, если не играет ни одна группа? Вы, конечно, не хотите пустую таблицу, и Handlebars, к счастью, предоставляет помощников, if , else и unless . Операторы if и else работают подобно большинству языков программирования: если передаваемый вами объект имеет значение false или false, выполняется оператор else . В противном if выполняется оператор if . unless утверждение довольно интересно; это по сути перевернутый оператор if . Если выражение имеет значение true , блок unless будет выполняться. Итак, давайте включим эти помощники в наш код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
{{#if Bands}}
    <table>
        <tr>
            <th>Band Name</th>
            <th>Date</th>
            <th>Album Name</th>
        </tr>
        {{#each Bands}}
            <tr>
                <td>{{Name}}</td>
                <td>{{Date}}</td>
                <td>{{Albums.0.Name}}</td>
            </tr>
        {{/each}}
    </table>
{{else}}
    <h3>There are no concerts coming up.</h3>
{{/if}}

Handlebars дает вам возможность создать свой собственный помощник. Просто зарегистрируйте свою функцию в Handlebars, и любой шаблон, скомпилированный впоследствии, сможет получить доступ к вашему помощнику. Вы можете сделать два вида помощников:

  • Помощники функций — это обычные функции, которые после регистрации могут вызываться в любом месте вашего шаблона. Handlebars записывает возвращаемое значение функции в шаблон.
  • Помощники блоков по своей природе аналогичны помощникам if , each и т. Д. Они позволяют вам изменить контекст того, что внутри.

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

Первый аргумент, переданный registerHelper() — это имя моего помощника по работе с клиентами; Я буду использовать это имя в шаблоне. Второй аргумент — это функция, связанная с этим помощником.

Использование этого помощника в шаблоне чрезвычайно просто:

1
{{Max 12 45}}

Этот шаблон использует помощника Max и передает значения 12 и 45 связанной функции. Помощники функции Handlebars поддерживают несколько параметров. Вы можете напрямую вставлять числа в сам шаблон или использовать атрибуты из структуры JSON.

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

Чтобы отобразить оба имени, вы можете написать вспомогательный блок, который запускает шаблон один раз с контекстом родителя и один раз с контекстом потомка. Вот помощник:

И шаблон выглядит так:

1
2
3
{{#BothNames this}}
    <h2>{{Name}}</h2>
{{/BothName}}

Хэш-тег перед именем помощника сообщает Handlebars, что это помощник блока, и вы закрываете блок почти так же, как HTML-тег. Функция options.fn запускает секцию шаблона внутри блока с любым контекстом, который вы ей предоставляете.

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


Вы не создаете сайт с Handlebars.

Шаблон, который мы создадим, предназначен для сайта рецептов. Это даст вам хорошее понимание Handlebars, поскольку оно включает получение данных из API и передачу их через шаблон.

Сначала мы должны загрузить наш шаблонный скрипт, но для этого нам нужно создать новый HTML-файл и включить нашу библиотеку Handlebars:

01
02
03
04
05
06
07
08
09
10
<html>
    <head>
        <title>Handlebars Demo</title>
        <script type=»text/javascript» src=»Handlebars.js»></script>
    </head>
    <body>
        <script id=»Handlebars-Template» type=»text/x-handlebars-template»>
        </script>
    </body>
</html>

Для удобства вы можете сохранить свой шаблон в элементе <script /> и загрузить его с помощью JavaScript. Это намного чище, чем хранить его непосредственно в переменной JavaScript.

Теперь давайте обсудим, как это приложение будет работать. Во-первых, приложение подключается к API (я использую Yummly) для получения информации о некоторых рецептах. Затем мы передаем эту информацию в Handlebars и запускаем ее через шаблон. Наконец, мы заменяем секцию body на новый сгенерированный HTML Это довольно простой процесс; Итак, давайте начнем с добавления второго блока script непосредственно перед закрывающим тегом body и создадим переменную Ajax :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script>
 
var Ajax = (window.XMLHttpRequest) ?
 
Ajax.onreadystatechange = function(){
    if (Ajax.readyState == 4 && Ajax.status == 200)
    {
        //Parse the JSON data
        var RecipeData = JSON.parse(Ajax.responseText);
         
        //Get the Template from above
        var Source = document.getElementById(«Handlebars-Template»).textContent;
         
        //Compile the actual Template file
        var Template = Handlebars.compile(Source);
         
        //Generate some HTML code from the compiled Template
        var HTML = Template({ Recipes : RecipeData });
         
        //Replace the body section with the new code.
        document.body.innerHTML = HTML;
    }
}
 
Ajax.open(«GET»,»Recipe.php», true);
Ajax.send();
 
</script>

Если данные вашего сайта регулярно меняются, вы можете посмотреть на Handlebars.

Это полный код для компиляции и генерации HTML-кода из шаблона. Технически вы можете передавать данные JSON из API непосредственно в Handlebars, но вы сталкиваетесь с проблемами перекрестного происхождения. Вместо того, чтобы совершать какие-то взломы или использовать PHP для «эхом» данных в переменную JavaScript, я решил поместить все это в отдельный файл: Recipe.php . Поэтому, прежде чем мы начнем создавать шаблон, давайте посмотрим на этот файл PHP.

API Yummly довольно прост. Нет сложной системы аутентификации; Вам просто нужно зарегистрироваться, получить некоторые учетные данные и вставить их в URL. Вы можете напрямую отобразить данные, если хотите, но мне нужна более подробная информация по каждому рецепту. Поэтому я обработаю данные из первого вызова API и сделаю второй запрос для каждого рецепта. Вот полный скрипт PHP:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
    //Empty Array to hold all the recipes
    $Json = [];
     
    $UserID = //Your ID Here;
     
    $UserKey = //Your Yummly key;
     
    //This searches Yummly for cake recipes
    $Recipes = file_get_contents(«http://api.yummly.com/v1/api/recipes?_app_id=» . $UserID . «&_app_key=» . $UserKey . «&maxResult=2&requirePictures=true&q=Cake»);
     
    //Decode the JSON into a php object
    $Recipes = json_decode($Recipes)->matches;
     
     
    //Cycle Through The Recipes and Get full recipe for each
    foreach($Recipes as $Recipe)
    {
        $ID = $Recipe->id;
        $R = json_decode(file_get_contents(«http://api.yummly.com/v1/api/recipe/» . $ID . «?_app_id=» . $UserID . «&_app_key=» . $UserKey . «&images=large»));
         
         
        //This is the data we are going to pass to our Template
        array_push($Json, array(
            Name => $R->name,
            Ingredients => $R->ingredientLines,
            Image => $R->images[0]->hostedLargeUrl,
            Yield => $R->yield,
            Flavors => $R->flavors,
            Source => array(
                Name => $R->source->sourceDisplayName,
                Url => $R->source->sourceRecipeUrl
            )
        ));
    }
     
    //Print out the final JSON object
    echo json_encode($Json);
?>

Создавая свой сайт с помощью шаблона Handlebars, вы можете создать полноценный код всего за несколько строк. Вот весь шаблон:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script id=»Handlebars-Template» type=»text/x-handlebars-template»>
    <div id=»Content»>
      <h1>&Xi;RecipeCards
        <span id=’BOS’>Recipe search powered by
            <a id=’Logo’ href=’http://www.yummly.com/recipes’>
                <img src=’http://static.yummly.com/api-logo.png’/>
            </a>
        
      </h1>
      {{#each Recipes}}
        <div class=’Box’>
            <img class=’Thumb’ src=»{{{Image}}}» alt=»{{Name}}»>
            <h3>{{Name}} <a id=’Logo’ href=»{{Source.Url}}»> — {{Source.Name}}</a></h3>
            <h5>{{getFlavor Flavors}}</h5>
            <h5>{{Yield}}</h5>
            <p>Ingredients:</p>
            <ul>
                {{#each Ingredients}}
                    <li>{{this}}</li>
                {{/each}}
            </ul>
        </div>
      {{/each}}
    </div>
</script>

Давайте пробежимся по этому коду. Первые семь строк — это просто логотип в верхней части страницы. Затем для каждого рецепта мы создаем «карточку» рецепта с изображением, названием и ингредиентами.

API Yummly возвращает список данных вкуса (то есть, насколько сладкий, кислый, пряный и т. Д.) Для каждого элемента. Я написал вспомогательный getFlavor который получает эту информацию и возвращает наиболее доминирующий вкус блюда. Чтобы этот шаблон работал, нам нужно загрузить помощник getFlavor в Handlebars перед getFlavor шаблона. Поэтому в начале второго раздела сценария добавьте следующий код перед кодом Ajax:

Теперь, когда Handlebars видит getFlavor , он вызывает связанную функцию и получает информацию о вкусе.

На этом этапе вы можете поиграть и разработать шаблон по своему усмотрению, но вы, скорее всего, увидите, что этот процесс идет медленно. Это связано прежде всего с тремя вызовами API, перед тем как Handlebars загрузит страницу. Очевидно, это не идеально, но прекомпиляция вашего шаблона может помочь.


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

Это также приводит к уменьшению размера файла, но это не очень помогает в нашем сценарии.

Наша проблема — связь между браузером и API. Если вы хотите предварительно скомпилировать шаблон, вы можете скачать пакет Node.js через npm с помощью следующей команды:

Вам может потребоваться сделать это как root (т.е. добавить ‘sudo’ перед командой). После установки вы можете создать файл для вашего шаблона и скомпилировать его так:

Вы должны дать вашему файлу .handlebars расширение .handlebars . Это не обязательно, но если вы demo.html что-то вроде demo.html , тогда имя шаблона будет «demo.html», а не просто «demo». После присвоения имени шаблону просто включите выходной файл вместе с версией Handlebars (вы можете использовать обычную версию, но она больше) и введите следующее:

Утверждение » unless является … по существу перевернутым выражением if .

Но, как я уже говорил, это не очень помогает нам в этом сценарии. Что тогда мы можем сделать? Ну, мы можем предварительно скомпилировать и вывести весь файл. Это позволяет нам запускать шаблон с данными и сохранять окончательный вывод HTML — другими словами, кеширование. Это значительно ускоряет время загрузки вашего приложения. К сожалению, клиентский JavaScript не поддерживает файловый ввод-вывод. Итак, самый простой способ сделать это — просто вывести HTML в текстовое поле и сохранить его вручную. Ознакомьтесь с рекомендациями API по кешированию. У большинства API есть максимальное количество времени, в течение которого данные могут быть кэшированы; убедитесь, что нашли эту информацию перед сохранением статических страниц.


Это было краткое введение в руль. Двигаясь вперед, вы можете заглянуть в «Partials» — небольшие шаблоны, которые можно использовать как функции. Как всегда, не стесняйтесь оставлять комментарий или вопрос в разделе комментариев ниже.