Элементы Angular с автономными компонентами¶
Начиная с версии Angular 14.2, появилась возможность использовать автономные компоненты в качестве элементов Angular. В этой главе я покажу вам, как работает эта новая возможность.
Исходный код
Предоставление автономного компонента¶
Автономный компонент, который я буду использовать здесь, — это простая кнопка переключения под названием ToggleComponent
:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
Установив инкапсуляцию на ViewEncapsulation.ShadowDom
, я заставляю браузер использовать "настоящий" Shadow DOM вместо эмулированного аналога Angular. Однако это также означает, что нам придется использовать API slot
браузера для проецирования контента, а не ng-content
Angular.
Установка Angular Elements¶
Хотя Angular Elements предоставляется непосредственно командой Angular, CLI не устанавливает его. Следовательно, мы должны сделать это вручную:
1 |
|
В былые времена @angular/elements
также поддерживал ng add
. Эта поддержка сопровождалась схемой добавления необходимого полифилла. Однако в настоящее время все браузеры, поддерживаемые Angular, могут работать с веб-компонентами нативно. Таким образом, необходимость в таком полифилле отпала, и поддержка ng add
была удалена несколько версий назад.
Загрузка с Angular Elements¶
Теперь давайте загрузим наше приложение и представим ToggleComponent
как веб-компонент (пользовательский элемент) с помощью Angular Elements. Для этого мы можем использовать функцию createApplication
, добавленную в Angular 14.2:
main.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Мы можем передать массив с провайдерами в createApplication
. Это позволит предоставлять сервисы вроде HttpClient
через корневую область приложения. В общем случае эта опция нужна, когда мы хотим настроить этих провайдеров, например, с помощью метода forRoot
или функции provideXYZ
. Во всех остальных случаях предпочтительнее просто использовать древовидные провайдеры (providedIn: 'root'
).
Результатом createApplication
является новый ApplicationRef
. Мы можем передать его инжектор вместе с ToggleComponent
в createCustomElement
. В результате мы получим пользовательский элемент, который можно зарегистрировать в браузере с помощью customElements.define
.
Обратите внимание, что текущий API не позволяет установить собственный экземпляр зоны, как, например, зона noop
. Вместо этого команда Angular хочет сконцентрироваться на новых функциях для обнаружения изменений без зон в будущем.
Побочное замечание: загрузка нескольких компонентов¶
Показанный API также позволяет создавать несколько пользовательских элементов:
1 2 3 4 5 6 7 |
|
Помимо работы с пользовательскими элементами, ApplicationRef
позволяет загружать несколько компонентов в качестве приложений Angular:
1 2 3 4 |
|
При загрузке компонента таким образом можно переписать используемый селектор. Обратите внимание, что для обнаружения изменений необходимо вызывать bootstrap
внутри зоны.
Изначально загрузка нескольких компонентов осуществлялась путем размещения нескольких компонентов в массиве bootstrap
вашего AppModule
. Однако функция bootstrapApplication
, используемая для загрузки автономных компонентов, не позволяет этого сделать, поскольку целью было предоставить простой API для наиболее распространенного случая использования.
Вызов элемента Angular¶
Чтобы вызвать наш элемент Angular, нам нужно просто поместить соответствующий тег в наш index.html
:
1 2 |
|
Поскольку пользовательский элемент воспринимается браузером как обычный узел DOM, мы можем использовать традиционные вызовы DOM для установки событий и присвоения значений свойствам:
1 2 3 4 5 6 7 8 9 10 11 |
|
Вызов веб-компонента в компоненте Angular¶
Если мы вызываем веб-компонент в компоненте Angular, мы можем напрямую привязать к нему данные, используя скобки для свойств и круглые скобки для событий. Это работает независимо от того, был ли веб-компонент создан в Angular или нет.
Чтобы продемонстрировать это, предположим, что у нас есть следующий AppComponent:
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 |
|
Этот автономный компонент вызывает наш веб-компонент my-toggle
. Хотя компилятор Angular знает обо всех возможных компонентах Angular, он не знает о веб-компонентах. Следовательно, при виде тега my-toggle
он будет выдавать ошибку. Чтобы избежать этого, нам нужно зарегистрировать схему CUSTOM_ELEMENTS_SCHEMA
.
Раньше мы делали это со всеми NgModules, которые хотели использовать вместе с веб-компонентами. Теперь мы можем напрямую зарегистрировать эту схему в автономных компонентах. Технически это просто отключает проверки компилятора относительно возможных имен тегов. Это двоичная схема — проверки либо включены, либо выключены — и нет способа напрямую сообщить компилятору о доступных веб-компонентах.
Чтобы этот компонент появился на нашей странице, нам нужно его загрузить:
main.ts | |
---|---|
1 2 3 4 5 6 7 |
|
Также нам нужно добавить элемент для AppComponent в index.html:
1 |
|
Бонус: компиляция самодостаточного бандла¶
Теперь предположим, что мы предоставляем только пользовательский элемент и не загружаем наш AppComponent
. Чтобы использовать этот пользовательский элемент в других приложениях, нам нужно скомпилировать его в самодостаточный бандл. В то время как традиционный сборщик на основе webpack создает несколько пакетов, например, основной пакет и пакет времени выполнения, новый ApplicationBuilder
на основе esbuild (см. главу esbuild и новый Application Builder) просто дает нам один пакет для нашего исходного кода и еще один для полифиллов.
Результирующие пакеты выглядят следующим образом:
1 2 3 4 5 |
|
Если вы используете свой веб-компонент на другом сайте, например, на CMS, просто ссылайтесь там на основной пакет и добавьте соответствующий тег. Также ссылайтесь на полифиллы. Однако при использовании нескольких таких пакетов необходимо убедиться, что полифиллы загружаются только один раз.
Заключение¶
Как побочный продукт автономных компонентов, Angular предоставляет упрощенный способ использования элементов Angular: Мы начинаем с создания ApplicationRef
, чтобы получить Injector
. Наряду с автономным компонентом мы передаем этот инжектор в Angular Elements. В результате мы получаем веб-компонент, который можно зарегистрировать в браузере.