От автора: динамические компоненты не всегда имеют одинаковую структуру. Иногда нам необходимо управлять многими различными состояниями. Это может быть полезно сделать асинхронно.
Пример использования
Шаблоны компонентов используются в Scrumpy в нескольких местах: уведомления, комментарии и вложения. Давайте рассмотрим комментарии, чтобы понять, что я на самом деле подразумеваю под этим.
Комментарии — это теперь не просто текстовые поля. Вы ожидаете, что сможете размещать в них ссылки, загружать изображения, встраивать видео и многое другое. Все эти совершенно разные элементы должны быть представлены в этом комментарии. Если вы попытаетесь сделать это в рамках одного компонента, он может быстро стать абсолютным беспорядочным.
Наиболее распространенные превью для ссылок — данные open graph, изображения и видео
Как мы можем справиться с этой проблемой? Вероятно, большинство людей будут проверять все случаи и после этого загружать определенные компоненты. Что-то вроде этого:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<template> <div class="comment"> // текст комментария <p>...</p> // изображение open graph <link-open-graph v-if="link.type === 'open-graph'" /> // обычное изображение <link-image v-else-if="link.type === 'image'" /> // встроенное видео <link-video v-else-if="link.type === 'video'" /> ... </div> </template> |
Однако код может стать очень громоздким и повторяющимся, если список поддерживаемых шаблонов становится длиннее и длиннее. В нашем случае это касается комментариев — просто подумайте о поддержке вложений для Youtube, Twitter, Github, Soundcloud, Vimeo, Figma … список бесконечен.
Шаблоны динамических компонентов
Другой способ — реализовать какой-то загрузчик, который загружает именно тот шаблон, который вам нужен. Это позволяет написать чистый компонент следующим образом:
1 2 3 4 5 6 7 8 9 |
<template> <div class="comment"> // текст комментария <p>...</p> // тип может быть 'open-graph', 'image', 'video'... <dynamic-link :data="someData" :type="type" /> </div> </template> |
Выглядит намного лучше, не так ли? Давайте посмотрим, как работает этот компонент. Во-первых, нам нужно изменить структуру папок для наших шаблонов.
Структура папок для шаблонов динамических компонентов
Лично мне нравится создавать папку для каждого компонента, потому что позже можно добавить другие файлы для стилей и тестов. Конечно, как вы хотите построить структуру, зависит от вас. Затем мы рассмотрим, как этот компонент dynamic-link собирается.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<template> <component :is="component" :data="data" v-if="component" /> </template> <script> export default { name: 'dynamic-link', props: ['data', 'type'], data() { return { component: null, } }, computed: { loader() { if (!this.type) { return null } return () => import(`templates/${this.type}`) }, }, mounted() { this.loader() .then(() => { this.component = () => this.loader() }) .catch(() => { this.component = () => import('templates/default') }) }, } </script> |
Так что здесь происходит? Динамические компоненты поддерживаются Vue.js по умолчанию. Проблема в том, что вам необходимо зарегистрировать / импортировать все компоненты, которые вы хотите использовать.
1 2 3 4 5 6 7 8 9 10 11 |
<template> <component :is="someComponent"></component> </template> <script> import someComponent from './someComponent' export default { components: { someComponent, }, } </script> |
Здесь ничего не добавляется, потому что мы хотим динамически использовать наши компоненты. Поэтому мы можем использовать динамический импорт из Webpack. Мы также используем вместе с ними вычисляемые значения, вот где происходит магия — да, вычисляемые значения могут возвращать функцию. Супер удобно!
1 2 3 4 5 6 7 8 |
computed: { loader() { if (!this.type) { return null } return () => import(`templates/${this.type}`) }, }, |
Когда наш компонент смонтирован, мы пытаемся загрузить шаблон. Если что-то пошло не так, мы можем установить резервный шаблон. Это может быть полезно для отображения сообщений об ошибках для пользователей.
1 2 3 4 5 6 7 8 9 |
mounted() { this.loader() .then(() => { this.component = () => this.loader() }) .catch(() => { this.component = () => import('templates/default') }) }, |
Заключение
Это может быть полезно, если у вас много разных представлений для одного компонента.
Это легко расширяемо.
Это асинхронно. Шаблоны загружаются только при необходимости.
Сохраняет DRY-код.
Это в основном все! Я хотел бы услышать, если вы уже используете эту технику?
Автор: Philipp Kühn
Источник: //medium.com/
Редакция: Команда webformyself.