Мы считаем Vue и веб-компоненты в первую очередь взаимодополняющими технологиями. Vue имеет отличную поддержку как использования, так и создания пользовательских элементов. Независимо от того, интегрируете ли вы пользовательские элементы в существующее приложение Vue или используете Vue для создания и распространения пользовательских элементов, вы находитесь в хорошей компании.
Использование пользовательских элементов в Vue
Vue набирает 100% баллов в тестах Custom Elements Everywhere. Использование пользовательских элементов внутри приложения Vue во многом работает так же, как использование собственных элементов HTML, но следует учитывать несколько моментов
Пропуск разрешения компонента
По умолчанию Vue попытается разрешить неродной HTML-тег как зарегистрированный компонент Vue, прежде чем вернуться к его рендерингу как пользовательскому элементу. Это приведет к тому, что Vue выдаст предупреждение «не удалось разрешить компонент» во время разработки. Чтобы сообщить Vue, что определенные элементы следует рассматривать как пользовательские элементы и пропускать разрешение компонентов, мы можем указать compilerOptions.isCustomElement опцию
Если вы используете Vue с настройкой сборки, этот параметр следует передавать через конфигурации сборки, поскольку это параметр времени компиляции.
# Пример конфигурации в браузере
# Пример конфигурации Vite
# Пример конфигурации Vue CLI
Передача свойств DOM
Поскольку атрибуты DOM могут быть только строками, нам необходимо передавать сложные данные пользовательским элементам в виде свойств DOM. При настройке реквизита для пользовательского элемента Vue 3 автоматически проверяет наличие свойства DOM с помощью inоператора и предпочитает установить значение как свойство DOM, если ключ присутствует. Это означает, что в большинстве случаев вам не придется об этом думать, если пользовательский элемент соответствует рекомендуемым рекомендациям
Однако могут быть редкие случаи, когда данные необходимо передать как свойство DOM, но пользовательский элемент неправильно определяет/отражает это свойство (что приводит к in сбою проверки). В этом случае вы можете принудительно v-bind установить привязку как свойство DOM, используя .prop модификатор
Создание пользовательских элементов с помощью Vue
Основное преимущество пользовательских элементов заключается в том, что их можно использовать с любой платформой или даже без нее. Это делает их идеальными для распространения компонентов, когда конечный потребитель может не использовать один и тот же стек внешнего интерфейса или когда вы хотите изолировать конечное приложение от деталей реализации используемых им компонентов.
# defineCustomElement
Vue поддерживает создание пользовательских элементов с использованием тех же API-интерфейсов компонентов Vue с помощью этого defineCustomElement метода. Метод принимает тот же аргумент, что и defineComponent, но вместо этого возвращает конструктор пользовательского элемента, который расширяет HTMLElement
Жизненный цикл
- connectedCallback Пользовательский элемент Vue смонтирует внутренний экземпляр компонента Vue внутри своего теневого корня при первом вызове элемента
- Когда элемент disconnectedCallback вызывается, Vue проверит, отсоединен ли элемент от документа после тика микрозадачи.
- Если элемент все еще находится в документе, это перемещение, и экземпляр компонента будет сохранен
- Если элемент отсоединен от документа, это удаление, и экземпляр компонента будет размонтирован
Props
- Все реквизиты, объявленные с использованием этой props опции, будут определены в пользовательском элементе как свойства. Vue автоматически обрабатывает отражение между атрибутами/свойствами, где это необходимо.
- Атрибуты всегда отражаются в соответствующих свойствах.
- Свойства с примитивными значениями (string или boolean) number отражаются как атрибуты.
- Vue также автоматически приводит реквизиты, объявленные с помощью Boolean или, Numberк желаемому типу, когда они установлены как атрибуты (которые всегда являются строками)
И использование пользовательского элемента:
В компоненте selected будет приведено к true(логическое значение) и index будет приведено к 1(число).
# События
События, создаваемые с помощью this.$emit или при настройке emit, отправляются как собственные CustomEvents в пользовательском элементе. Дополнительные аргументы события (полезная нагрузка) будут представлены в виде массива объекта CustomEvent в качестве его detail свойства.
# Слоты
Внутри компонента слоты можно визуализировать с помощью элемента, как обычно. Однако при использовании результирующего элемента он принимает только собственный синтаксис слотов
- Слоты с ограниченной областью действия не поддерживаются.
- При передаче именованных слотов используйте slot атрибут вместо директивы v-slot
# Предоставление / внедрение
API Provide / Inject и его эквивалент Composition API также работают между пользовательскими элементами, определенными в Vue. Однако обратите внимание, что это работает только между пользовательскими элементами . т. е. пользовательский элемент, определенный Vue, не сможет внедрять свойства, предоставляемые компонентом Vue, не являющимся пользовательским элементом.
SFC как пользовательский элемент
defineCustomElement также работает с однофайловыми компонентами Vue (SFC). Однако при настройке инструментов по умолчанию styleвнутренняя часть SFC все равно будет извлечена и объединена в один файл CSS во время производственной сборки. При использовании SFC в качестве пользовательского элемента часто желательно styleвместо этого внедрить теги в теневой корень пользовательского элемента.
Официальные инструменты SFC поддерживают импорт SFC в «режиме пользовательского элемента» (требуется @vitejs/plugin-vue@^1.4.0или vue-loader@^16.5.0). SFC, загруженный в режиме пользовательского элемента, встраивает свои style теги в виде строк CSS и предоставляет их в соответствии с параметром компонента styles. Это будет подхвачено defineCustomElement и введено в теневой корень элемента при создании экземпляра.
Чтобы включить этот режим, просто завершите имя файла компонента на .ce.vue
Если вы хотите настроить, какие файлы должны быть импортированы в режиме настраиваемых элементов (например, рассматривать все SFC как настраиваемые элементы), вы можете передать эту customElement опцию соответствующим плагинам сборки
- @vitejs/plugin-vue
- vue-загрузчик
# Советы по использованию библиотеки пользовательских элементов Vue
При создании пользовательских элементов с помощью Vue элементы будут полагаться на среду выполнения Vue. Базовый размер составляет около 16 КБ в зависимости от количества используемых функций. Это означает, что не идеально использовать Vue, если вы поставляете один пользовательский элемент — вы можете использовать ванильный JavaScript, petite-vue или фреймворки, которые специализируются на небольшом размере среды выполнения. Однако базовый размер более чем оправдан, если вы отправляете коллекцию пользовательских элементов со сложной логикой, поскольку Vue позволит создавать каждый компонент с гораздо меньшим количеством кода. Чем больше элементов вы отправляете вместе, тем выгоднее компромисс.
Если пользовательские элементы будут использоваться в приложении, которое также использует Vue, вы можете экспортировать Vue из встроенного пакета, чтобы элементы использовали ту же копию Vue из хост-приложения.
Рекомендуется экспортировать отдельные конструкторы элементов, чтобы предоставить пользователям возможность импортировать их по требованию и регистрировать с нужными именами тегов. Вы также можете экспортировать удобную функцию для автоматической регистрации всех элементов. Вот пример точки входа в библиотеку пользовательских элементов Vue:
Если у вас много компонентов, вы также можете использовать функции инструмента сборки, такие как импорт glob Vite или веб-пакет, require.context для загрузки всех компонентов из каталога.
Веб-компоненты и машинописный текст
Если вы разрабатываете приложение или библиотеку, вы можете проверить тип своих компонентов Vue, включая те, которые определены как пользовательские элементы.
Пользовательские элементы регистрируются глобально с использованием собственных API, поэтому по умолчанию они не будут иметь определения типа при использовании в шаблонах Vue. Чтобы обеспечить поддержку типов для компонентов Vue, зарегистрированных как пользовательские элементы, мы можем зарегистрировать глобальные типизации компонентов, используя интерфейс GlobalComponents в шаблонах Vue и/или в JSX
Веб-компоненты против компонентов Vue
Некоторые разработчики считают, что следует избегать моделей компонентов, принадлежащих инфраструктуре, и что исключительное использование пользовательских элементов делает приложение «готовым к будущему». Здесь мы попытаемся объяснить, почему мы считаем такой взгляд на проблему слишком упрощенным.
Действительно, существует определенный уровень совпадения функций между пользовательскими элементами и компонентами Vue: они оба позволяют нам определять повторно используемые компоненты с передачей данных, отправкой событий и управлением жизненным циклом. Однако API-интерфейсы веб-компонентов являются относительно низкоуровневыми и простыми.
Чтобы создать настоящее приложение, нам нужно немало дополнительных возможностей, которые платформа не обеспечивает:
- Декларативная и эффективная система шаблонов;
- Реактивная система управления состоянием, которая облегчает извлечение и повторное использование межкомпонентной логики;
- Эффективный способ рендеринга компонентов на сервере и их гидратации на клиенте (SSR), что важно для показателей SEO и Web Vitals, таких как LCP . SSR собственных пользовательских элементов обычно включает в себя моделирование DOM в Node.js и последующую сериализацию измененного DOM, в то время как Vue SSR компилируется в конкатенацию строк, когда это возможно, что гораздо более эффективно.
Модель компонентов Vue разработана с учетом этих потребностей как целостная система.
Имея компетентную команду инженеров, вы, вероятно, могли бы создать эквивалент поверх собственных пользовательских элементов, но это также означает, что вы берете на себя долгосрочное бремя обслуживания собственной структуры, теряя при этом экосистему и преимущества сообщества. зрелая среда, такая как Vue.
Существуют также платформы, построенные с использованием пользовательских элементов в качестве основы их компонентной модели, но все они неизбежно должны внедрять свои собственные решения для проблем, перечисленных выше. Использование этих фреймворков влечет за собой принятие их технических решений о том, как решить эти проблемы, что, несмотря на то, что может рекламироваться, не защитит вас автоматически от потенциальных будущих оттоков.
Есть также некоторые области, в которых пользовательские элементы оказываются ограниченными:
- Нетерпеливая оценка слотов затрудняет композицию компонентов. Слоты Vue с ограниченной областью действия — это мощный механизм для композиции компонентов, который не может поддерживаться пользовательскими элементами из-за нетерпеливого характера собственных слотов. Нетерпеливые слоты также означают, что принимающий компонент не может контролировать, когда и нужно ли отображать часть содержимого слота.
- Доставка пользовательских элементов с помощью CSS с теневой областью DOM сегодня требует встраивания CSS в JavaScript, чтобы их можно было внедрить в теневые корни во время выполнения. Они также приводят к дублированию стилей разметки в сценариях SSR. В этой области работают некоторые функции платформы , но на данный момент они еще не поддерживаются повсеместно, и все еще существуют проблемы производительности/SSR, которые необходимо решить. Между тем, Vue SFC предоставляет механизмы области видимости CSS , которые поддерживают извлечение стилей в простые файлы CSS.
Vue всегда будет в курсе последних стандартов веб-платформы, и мы с радостью будем использовать все, что предоставляет платформа, если это облегчит нашу работу. Однако наша цель — предоставить решения, которые хорошо работают и работают сегодня. Это означает, что мы должны внедрять новые функции платформы с критическим мышлением, а это предполагает заполнение пробелов, в которых стандарты не соответствуют требованиям, хотя это все еще актуально.