Работа с шаблонами в Vue.js 2

Работа с шаблонами в Vue.js 2
mangohost

Vue.js 2 представил свою собственную реализацию Virtual DOM. На первый взгляд, кажется что это никак не отразится на том как вы пишите шаблоны. Из документации:

Под капотом, Vue компилирует шаблоны в render-функции для Virtual DOM. В совокупности с системой реактивности, Vue способен грамотно определять минимальное количество компонентов для повторной визуализации и выполнять минимальное количество действий с DOM при изменении состояния приложения.

Virtual DOM освобождает от довольно большой части оптимизации: теперь вы можете предварительно скомпилировать шаблоны в чистый JavaScript, таким образом Vue.js может не делать этого в браузере.

Без предварительной компиляции шаблонов в процессе сборки, Vue.js будет переводить строковый шаблон в JavaScript render-функцию, во время выполнения. Это означает, что на этапе начального рендеринга потребуется больше времени, по двум причинам: ваш уже собранный скрипт должен включать в себя Vue компилятор (больше время для загрузки) и шаблон должен быть скомпилирован, перед тем как он будет использован (больше время выполнение).

Эта статья не о синтаксисе шаблонов в Vue.js 2, а о том где и как определять ваши шаблоны. Я написал её, потому что на текущий момент не нашёл ни одного ресурса, который бы на самом деле объединил различные способы управления вашими шаблонами.

Я разделил различные способы определения шаблонов на 3 разные категории, у каждой из которых есть собственные преимущества и недостатки:

  • Написание шаблонов, которые компилируются во время выполнения (наименьшая производительность);
  • Использование отдельного .vue файла для компонентов (требуется этап сборки);
  • Ручное написание render-функций (чистый JavaScript, не HTML-подобный синтаксис);

Использование не скомпилированных шаблонов

Шаблоны в Vue.js необязательно должны быть скомпилированы. Если вы используете runtime версию Vue.js, то шаблоны могут быть скомпилированы прямо в браузере. Это решение отличается простотой. Никаких лишних этапов сборки или специальных типов файлов, но такой подход жертвует производительностью. Первый рендеринг компонента займёт больше времени, потому что шаблон сначала необходимо скомпилировать в JavaScript.

Определение шаблонов в компоненте

Самый простой способ определить шаблон компонента - это определить его в параметре template.

// greeter.js

Vue.component('greeter', {

    template: '<div> Hello, {{ name }}!</div>',

    props: ['name'],
});

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

// greeter.js

Vue.component('greeter', {

    template: `
        <div>
            Hello, {{ name }}!
        </div>
    `,

    props: ['name'],
});

Кроме того, если вы используете такие сборщики как Webpack или Browserify, вы можете определить шаблон в отдельном файле. Параметр template может принимать значение require.

// greeter.js

Vue.component('greeter', {

    template: require('./greeter.html'),

    props: ['name'],
});
// greeter.html.js

module.exports = `
    <div>Hello, {{ name }}!</div>
`;

Определение шаблонов в атрибуте type="x-template" тега script

Тег script с атрибутом x-template может содержать шаблон, к которому компонент будет обращаться по ID.

// greeter.js

Vue.component('greeter', {

    template: '#greeter',

    props: ['name'],
});
<!-- index.html -->

<script type="text/x-template" id="greeter">
    <div>Hello, {{ name }}!</div>
</script>

На самом деле, это решение не очень, так как оно создаёт довольно большой разрыв между вашими шаблонами и компонентами, а по факту не приносит никакой пользы (даже официальная документация отговаривает нас от использования x-template).

Использование inline-template атрибута

С помощью специального атрибута inline-template, шаблон может быть указан во внутреннем содержании компонента.

// index.js

Vue.component('greeter', {
    props: ['name'],
});

new Vue({
    el: '#app',
});
<!-- index.html -->

<div id="#app">
    <greeter inline-template>
        Hello, {{ name }}!
    </greeter>
</div>

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

Документация

Использование отдельного файла компонента (.vue файлов)

Отдельный файл компонента существовал уже в первой версии Vue.js. В Vue.js 2 он приносит больше пользы: шаблоны будут предварительно скомпилированы в чистый JavaScript.

Vue файлы позволяют вам определять шаблон и скрипт в отдельном файле, который будет скомпилирован в JavaScript с помощью Webpack или Browserify.

<!-- Greeter.vue -->

<template>
    <div>Hello, {{ name }}!</div>
</template>

<script>
export default {
    props: ['name'],
};
</script>

Отдельные файлы компонента также открывают дверь более интересным возможностям, таким как написание шаблонов с помощью HTML или CSS препроцессоров. Это означает, что вы можете писать шаблоны например с помощью Pug (формально Jade).

<!-- Greeter.vue -->

<template lang="pug">
div Hello, {{ name }}!
</template>

<script>
export default {
    props: ['name'],
};
</script>

<style lang="sass" scoped>
div {
  text-decoration: blink;
}
</style>

Обратите внимание на то, что поскольку вы используете специальный тип файла, становиться труднее добавлять другие инструменты в ваш проект. Например, если вы хотите писать тесты или анализаторы (lint'ы) для ваших компонентов, то сначала их нужно скомпилировать, а также у редакторов кода могут возникнуть проблемы с .vue файлами.

Документация

Использование render-функций

Написание сырых render-функций

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

Написание ваших собственных render-функций даёт вам максимальную производительность без стадии сборки, но дело в том, что они не HTML-подобные и с ними труднее работать.

// greeter.jsx

Vue.component('greeter', {

    render(h) {
        return h('div', `Hello, ${this.name}!`);
    },

    props: ['name'],
});

Документация

Написание render-функций с помощью JSX

render-функции могут быть написаны в JSX формате с помощью плагина Babel, что позволяет достичь более HTML-подобного синтаксиса.

// greeter.jsx

Vue.component('greeter', {

    render(h) {
        return (
            <div>
                Hello, {{ name }}!
            </div>
        );
    },

    props: ['name'],
});

Обратите внимание на то, что большинство встроенных во Vue.js 2 директив не будут доступны при использовании JSX, но обычно у них есть собственные программные эквиваленты (например, вы можете заменить v-if на обычный if из JavaScript).

Документация

Вывод

Если вы разрабатываете большое приложение, в котором производительность является очень важным фактором (обычно SPA) или заинтересованы в использовании препроцессоров, то кажется вам подойдут отдельные файлы для Vue компонентов.

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

Комментарии

16 января 2017 13:15
vovanx

Хотелось бы следить за новыми постами где-нибудь во ВКонтакте или телеграме.

16 января 2017 14:11
Администратор

Единственный вариант на данный момент, это RSS https://wp.tuhub.ru/feed

13 июня 2017 18:27
sau

Нет , пилить до уровня Angular2 будут еще долго , если даже такие базовые вещи как динамическая загрузка и компиляция шаблонов лежат за рамками фреймворка. И это только первый поверхностный взгляд , а если попробовать применить в серьезных проектах ? - придется еще 100500 библиотек юзать.

mangohost