Работа с компонентами в фреймворке Vue

Если мы посмотрим на какой-нибудь сайт, то можем выделить на нем некоторые блоки: хедер, контент, сайдбар, футер.

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

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

Итак, давайте приступим к изучению компонентов.

Простой компонент

Во Vue компонент делается с помощью метода Vue.component. Этот метод первым параметром принимает название нашего компонента, а вторым - объект настроек:

Vue.component(название компонента, { настройки });

Все компоненты следует создавать до команды new Vue:

Vue.component(название компонента, { настройки }); let app = new Vue({ el: '#app', });

Давайте сделаем компонент с названием my-component:

Vue.component('my-component', { настройки }); let app = new Vue({ el: '#app', });

Давайте теперь добавим настройки нашему компоненту. Первая и самая главная настройка - это template. С ее помощью мы должны задать HTML код, который будет результатом работы нашего компонента.

Давайте добавим эту настройку:

Vue.component('my-component', { template: '<div>Пользовательский компонент!</div>', }); let app = new Vue({ el: '#app', });

Обратите внимание на то, что результат работы Vue.component мы никуда не записываем. Это и не нужно, ведь с помощью Vue.component просто происходит регистрация нового компонента. И после регистрации мы можем вставить этот компонент в любое место нашего HTML кода нашего Vue приложения.

Сейчас наше приложение Vue размещается в <div id="app">. Наш компонент называется my-component. Мы можем вставить результат работы нашего компонента в любое место <div id="app"> следующим образом: <my-component></my-component> - то есть каждому компоненту соответствует тег с таким же названием.

Давайте сделаем это:

<div id="app"> <my-component></my-component> </div>

Ну, а теперь соберем все вместе и запустим:

Vue.component('my-component', { template: '<div>Пользовательский компонент!</div>', }); let app = new Vue({ el: '#app', }); <div id="app"> <my-component></my-component> </div>

В результате выполнения этого кода вместо тега компонента <my-component></my-component> подставится результат работы этого компонента, то есть содержимое его настройки template.

Результат будет таким:

<div id="app"> <div class="task">Пользовательский компонент!</div> </div>

Передача данных в компонент

Сейчас у нас есть основной компонент, который мы создали с помощью new Vue и дочерний компонент my-component.

Как вы хорошо знаете, у основного компонента есть настройка data, внутри которой хранятся данные. Однако, наш дочерний компонент my-component не имеет доступа к этим данным - и это правильно: родительский компонент должен четко сказать, какие данные он хочет передать дочернему, а какие - нет.

Давайте передадим данные в наш компонент my-component. Пусть, к примеру, у нас есть имя 'Вася'. Передадим это имя в компонент так, чтобы к нему можно было обратиться внутри нашего компонента через фигурные скобки, вот так: {{ name }}.

Для этого нужно сделать следующее: вместо <my-component> написать <my-component name="Вася">, вот так:

<div id="app"> <my-component name="Вася"></my-component> </div>

Теперь внутри настройки template нашего компонента мы можем написать {{ name }} и вместо этого в результате подставится имя 'Вася'.

Сделаем это:

Vue.component('my-component', { template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', });

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

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

Атрибуты пишутся в виде массива. У нас пока есть только один атрибут - name, поэтому давайте укажем его:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', });

Пришло время собрать все вместе и запустить. Сделаем это:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', }); <div id="app"> <my-component name="Вася"></my-component> </div>

Результатом выполнения этого кода будет следующий HTML:

<div id="app"> <div class="task">Привет, Вася!</div> </div>

Несколько атрибутов

Как вы уже поняли, можно передавать несколько атрибутов. Давайте кроме имени передадим еще и фамилию:

<div id="app"> <my-component name="Вася" surname="Иванов"></my-component> </div> Vue.component('my-component', { props: ['name', 'surname'], template: '{<div>}Привет, {{ name }} {{ surname }}!</div>', }); let app = new Vue({ el: '#app', });

Результатом выполнения этого кода будет следующий HTML:

<div id="app"> <div class="task">Привет, Вася Иванов!</div> </div>

Зачем нам компоненты?

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

Пусть у нас есть компонент my-component, который мы уже сделали ранее:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', });

Используем наш компонент несколько раз, передав в него разные имена:

<div id="app"> <my-component name="Коля"></my-component> <my-component name="Вася"></my-component> <my-component name="Петя"></my-component> </div>

Давайте запустим:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', }); <div id="app"> <my-component name="Коля"></my-component> <my-component name="Вася"></my-component> <my-component name="Петя"></my-component> </div>

Результатом выполнения этого кода будет следующий HTML:

<div id="app"> <div class="task">Привет, Коля!</div> <div>Привет, Вася!</div> <div>Привет, Петя!</div> </div>

То есть один и тот же компонент можно использовать несколько раз с различными параметрами.

Какое в этом преимущество: если мы захотим поправить вывод имени на экран - нам придется это сделать только в одном месте, тут: template: '<div>Привет, {{ name }}!</div>'.

Получается, что в нашем случае дочерний компонент знает, как отобразить данные, но не знает, откуда они берутся. А родительский компонент наоборот - имеет данные, но не занимается их отображением, а поручает это дочерним компонентам.

Таким образом мы отделяем данные от их представления на экране и тем самым получаем более удобный в поддержке код.

В чем удобство: хотим поправить вывод данных - правим дочерний компонент и не боимся при этом, что где-то что-то сломаем.

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

Передача свойств из data

Пусть у нас теперь 'Вася' хранится в свойстве value объекта data:

let app = new Vue({ el: '#app', data: { value: 'Вася', } });

Чтобы передать данные из свойства value нам нужно будет сделать не name="value", а v-bind:name="value":

<div id="app"> <my-component v-bind:name="value"></my-component> </div>

Если написать просто name="value", то в компонент передастся строка 'value', а не содержимое свойства value.

Давайте совместим все вышеописанное и запустим:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', data: { value: 'Вася', } }); <div id="app"> <my-component v-bind:name="value"></my-component> </div>

Результатом выполнения этого кода будет следующий HTML:

<div id="app"> <div class="task">Привет, Вася!</div> </div>

Итак, данные из data родительского компонента можно передавать в дочерний через директиву v-bind.

Компоненты и циклы

Пусть теперь в свойстве values хранится массив имен:

let app = new Vue({ el: '#app', data: { values: ['Коля', 'Вася', 'Петя'], // массив имен } });

Давайте применим к свойству values директиву v-for и с ее помощью повторим наш компонент my-component в цикле:

<div id="app"> <my-component v-for="value in values"></my-component> </div>

Так можно делать и при это переменная value становится доступна в атрибутах нашего компонента. Давайте передадим ее в компонент с помощью директивы v-bind:

<div id="app"> <my-component v-for="(value, index) in values" v-bind:name="value" > </my-component> </div>

Есть еще один нюанс. Чтобы Vue проще было работать с компонентами, нам необходимо указать ключ через v-bind:key (подобное мы уже проходили при работе с обычными циклами):

<div id="app"> <my-component v-for="(value, index) in values" v-bind:name="value" v-bind:key="index" > </my-component> </div>

Итак, давайте напишем полный код и запустим его:

Vue.component('my-component', { props: ['name'], template: '<div>Привет, {{ name }}!</div>', }); let app = new Vue({ el: '#app', data: { values: ['Коля', 'Вася', 'Петя'], } }); <div id="app"> <my-component v-for="(value, index) in values" v-bind:name="value" v-bind:key="index" > </my-component> </div>

Результатом выполнения этого кода будет следующий HTML:

<div id="app"> <div class="task">Привет, Коля!</div> <div>Привет, Вася!</div> <div>Привет, Петя!</div> </div>

Итак, компоненты можно и нужно перебирать в цикле - это достаточно удобно.