Базовый пример
Компоненты — это переиспользуемые экземпляры Vue со своим именем.
Компоненты можно переиспользовать столько раз, сколько захотите
Обратите внимание, при нажатиях на кнопки, каждая изменяет свой собственный, отдельный count. Это потому, что каждый раз когда вы используете компонент будет создан его новый экземпляр.
Свойство data должно быть функцией
При определении компонента button-counter вы могли заметить, что data не была представлена в виде объекта, например так
Вместо этого свойство data у компонентов должно быть функцией, чтобы каждый экземпляр компонента управлял собственной независимой копией возвращаемого объекта данных
Если бы не было этого правила, нажатие на одну кнопку повлияло бы на данные всех других экземпляров
Организация компонентов
Обычно приложение организуется в виде дерева вложенных компонентов
Например, у вас могут быть компоненты для заголовка, боковой панели, зоны контента, каждый из которых может содержать другие компоненты для навигационных ссылок, постов блога и т.д.
Чтобы использовать эти компоненты в шаблонах, они должны быть зарегистрированы, чтобы Vue узнал о них. Есть два типа регистрации компонентов: глобальная и локальная. До сих пор мы регистрировали компоненты только глобально, используя Vue.component
Компоненты, зарегистрированные глобально, могут использоваться в шаблоне любого корневого экземпляра Vue (new Vue) созданного впоследствии — и даже внутри всех компонентов, расположенных в дереве компонентов этого экземпляра Vue.
Передача данных в дочерние компоненты через входные параметры
Ранее мы создавали компонент для записи блога. Проблема в том, что этот компонент бесполезен, если не будет возможности передавать ему данные, такие как заголовок и содержимое записи блога, которую мы хотим показать. Вот для чего нужны входные параметры.
Входные параметры — это пользовательские атрибуты, которые вы можете установить на компоненте. Когда значение передаётся в атрибут входного параметра, оно становится свойством экземпляра компонента. Чтобы передать заголовок в компонент нашей записи блога, мы можем включить его в список входных параметров, которые принимает компонент, с помощью опции props
Компонент может принимать столько входных параметров, сколько захотите, и по умолчанию любое значение может быть передано в любой входной параметр. В шаблоне выше вы увидите, что мы можем получить доступ к этому значению в экземпляре компонента, как и к любому свойству data
После объявления входного параметра вы можете передавать данные в него через пользовательский атрибут, например:
Однако, в типичном приложении у вас наверняка будет массив записей в data
Тогда нужно отобразить компонент для каждой записи
Как мы видим выше, можно использовать v-bind для динамической передачи данных во входные параметры. Это особенно полезно, когда вы не знаете заранее точного содержимого, которое потребуется отобразить, например после загрузки записей блога из API.
Один корневой элемент
При создании компонента blog-post, ваш шаблон в конечном итоге будет содержать не только название
По крайней мере, вы захотите отобразить и содержимое записи в блог
Однако, если вы попробуете сделать это в шаблоне, Vue покажет ошибку с пояснением что каждый компонент должен иметь один корневой элемент. Вы можете исправить эту ошибку, обернув шаблон в родительский элемент, например так:
По мере роста нашего компонента, вероятно, нам может понадобиться не только заголовок и содержание поста блога, но и дата публикации, комментарии и так далее. Определять входной параметр для каждой связанной части информации может стать очень раздражающим:
Это подходящее время для рефакторинга компонента blog-post, чтобы вместо длинного списка принимать лишь один входной параметр post
Теперь, когда добавляется новое свойство в объект post, оно будет автоматически доступно внутри blog-post
Прослушивание событий из дочерних компонентов в родительских компонентах
По мере разработки нашего компонента blog-post для некоторых возможностей может потребоваться передавать данные обратно в родительский компонент. Например, мы можем решить включить функцию для доступности, чтобы увеличивать размер текста в записях блога, оставив остальную часть страницы с размером текста по умолчанию.
В родительском компоненте мы можем добавить свойство postFontSize для этой возможности:
Которое будет использоваться в шаблоне для управления размером шрифта для всех записей блога:
Теперь давайте добавим кнопку для увеличения текста прямо перед содержимым каждой записи блога:
Проблема в том, что эта кнопка ничего не делает:
Когда мы нажимаем на кнопку, нужно сообщить родительскому компоненту, что ему необходимо увеличить размер текста для всех записей блога. К счастью, экземпляры Vue предоставляют собственную систему событий для решения этой проблемы. Родительский компонент может прослушивать любые события на экземпляре дочернего компонента с помощью v-on, как мы это делаем с нативными событиями DOM:
Затем дочерний компонент может сгенерировать событие с помощью встроенного метода $emit, передавая ему имя события:
Благодаря прослушиванию события v-on:enlarge-text="postFontSize += 0.1", родительский компонент отследит событие и обновит значение postFontSize
Передача данных вместе с событием
Иногда бывает полезно отправить определённые данные вместе с событием. Например, если захотим, чтобы компонент blog-post отвечал за то, насколько нужно увеличивать текст. В таком случае, мы можем использовать второй параметр $emit для предоставления этого значения:
Затем, когда мы прослушиваем событие в родителе, мы можем получить доступ к данным, переданным с событием, через $event
Или, если обработчик события будет методом:
Тогда значение будет передано первым аргументом:
Использование v-model на компонентах
Пользовательские события также могут использоваться для создания нестандартных элементов ввода, которые работают через v-model. Не забывайте, что:
делает то же самое, что и:
При использовании на компоненте, v-model вместо этого делает следующее:
Чтобы это действительно работало, элемент input внутри компонента должен:
- Привязывать значение атрибута value к входному параметру value
- По событию input генерировать собственное пользовательское событие input с новым значением
Вот это в действии
Теперь v-model будет прекрасно работать с этим компонентом
Распределение контента слотами
Как и с обычными HTML-элементами, часто бывает полезным передать компоненту содержимое, например
К счастью, эта задача легко решается с помощью пользовательского элемента у Vue:
Как вы видите выше, мы просто добавляем слот там, куда хотим подставлять контент — и это всё. Готово!
Динамическое переключение компонентов
Иногда бывает полезно динамически переключаться между компонентами, например в интерфейсе с вкладками
Показанное выше стало возможным с помощью элемента Vue со специальным атрибутом is
В примере выше currentTabComponent может содержать:
- имя зарегистрированного компонента, или
- объект с настройками компонента
Обратите внимание, атрибут может использоваться и с обычными HTML-элементами, однако они будут рассматриваться как компоненты, а это значит, что все атрибуты будут привязываться как DOM-атрибуты. Для того чтобы некоторые свойства, такие как value работали так, как вы ожидаете, следует привязывать их с использованием модификатора .prop
Особенности парсинга DOM-шаблона
Некоторые HTML-элементы, такие как ul, ol, table и select имеют ограничения на то, какие элементы могут отображаться внутри них, или например элементы, такие как li, tr и option могут появляться только внутри других определённых элементов.
Это приведёт к проблемам при использовании компонентов с элементами, которые имеют такие ограничения. Например:
Пользовательский компонент blog-post-row будет поднят выше, так как считается недопустимым содержимым, вызывая ошибки в итоговой отрисовке. К счастью, специальный атрибут is предоставляет решение этой проблемы:
Следует отметить, что этого ограничения не будет если вы используете строковые шаблоны из одного из следующих источников:
- Строковые шаблоны (например, template: '...')
- Однофайловые (.vue) компоненты
- script type="text/x-template"
На данный момент это всё, что вам нужно знать об особенностях парсинга DOM-шаблонов — и на самом деле это окончание раздела "Для начинающих" в нашем интерактивном учебнике по Vue. Наши поздравления! Ещё есть чему поучиться, но мы рекомендуем сначала пройти все тесты и практические упражнения в этом разделе. Удачи!