Перевод статьи с официального сайта документации Angular
Довольно часто нужно создавать компоненты, которые служат в качестве контейнера для различного типа контета. Например, вы хотите создать камстомный компонент карточку (CustomCard
):
@Component({ selector: 'custom-card', template: '<div class="card-shadow"> <!-- card content goes here --> </div>', }) export class CustomCard {/* ... */}
Вы можете использовать <ng-content>
элемент в качестве метки, которая укажет на местоположение вашего будущего контента.
@Component({ selector: 'custom-card', template: '<div class="card-shadow"> <ng-content></ng-content> </div>', }) export class CustomCard {/* ... */}
<aside> 💡
<ng-content>
работает аналогично нативному компоненту <slot>
, но с некоторой Angular-специфичной функциональностью.
</aside>
Когда вы используете компонент совместно с <ng-content>
, любой дочерний компонент хост-компонента будет рендериться (отображаться), или по-другому проецироваться, в местоположение <ng-content>
:
// Компонент источник @Component({ selector: 'custom-card', template: ` <div class="card-shadow"> <ng-content /> </div> `, }) export class CustomCard {/* ... */}
<!-- Использование компонента --> <custom-card> <p>This is the projected content</p> </custom-card>
<!-- отрендеренный DOM --> <custom-card> <div class="card-shadow"> <p>This is the projected content</p> </div> </custom-card>
Angular относится к любому дочернему компоненту, переданному таким путем, как к содержимому ****компонента. Это отличается от представления компонента, которое относится к элементам, определенным в шаблоне этого компонента.
<ng-content>
элемент не является ни компонентом, ни DOM элементом. Напротив, это специальная метка или указатель, который указывает Angular, где ему необходимо отрендерить контент. Компилятор Angular обрабатывает все элементы <ng-content>
во время сборки. Вы не сможете вставить, удалить или изменить <ng-content>
во время выполнения (в режиме реального времени). Вы не можете добавить директивы, стили или произвольные атрибуты в <ng-content>
.
<ng-content>
не подходит для использования с условиями через @if
, @for
, или @switch
. Angular в любом случае создает экземпляры и DOM — ноды для контента, отрендеренного с помощью метки <ng-content>
, даже в тех ситуациях, когда <ng-content>
скрыт. Для условного рендеринга контента больше подходит ng-template
.
Множественное отображение контента
Angular поддерживает отображение нескольких элементов с помощью нескольких <ng-content>
меток (плейсхолдеров), используя CSS-селекторы. Расширив пример карточки выше, вы можете создать два плейсхолдера для заголовка и тела, используя атрибут select
:
<!-- Шаблон компонента --> <div class="card-shadow"> <ng-content select="card-title"></ng-content> <div class="card-divider"></div> <ng-content select="card-body"></ng-content> </div>
<!-- Использование компонента --> <custom-card> <card-title>Hello</card-title> <card-body>Welcome to the example</card-body> </custom-card>
<!-- отрендеренный(сгенерированный) DOM --> <custom-card> <div class="card-shadow"> <card-title>Hello</card-title> <div class="card-divider"></div> <card-body>Welcome to the example</card-body> </div> </custom-card>
<ng-content>
поддерживает те же CSS-селекторы, что и компоненты.
Если вы используете один или более <ng-content>
с select
атрибутом и один <ng-content>
без атрибута, то последний из них (<ng-content>
без атрибута) будет отображать все элементы, которые не совпадают по заданному select
атрибуту:
<!-- Шаблон компонента --> <div class="card-shadow"> <ng-content select="card-title"></ng-content> <div class="card-divider"></div> <!-- отображаем все здесь, исключая "card-title" --> <ng-content></ng-content> </div>
<!-- Использование компонента --> <custom-card> <card-title>Hello</card-title> <img src="..." /> <p>Welcome to the example</p> </custom-card>
<!-- Срендеренный DOM --> <custom-card> <div class="card-shadow"> <card-title>Hello</card-title> <div class="card-divider"></div> <img src="..." /> <p>Welcome to the example></p> </div> </custom-card>
Если компонент не включает в себя <ng-content>
без атрибута select
, то любые элементы, которые не имеют соответствия с одной из меток <ng-content>
компонента с атрибутом, в конечном итоге не будут отрендерены DOM. c
Контент по-умолчанию
Angular обладает возможностью отображать контент по-умолчанию для <ng-content>
компонента на случай, если компонент не имеет никакого подходящего содержимого (дочернего контента). Вы можете определить контент по-умолчанию добавив дочерний контент внутрь элемента <ng-content>
самостоятельно.
<!-- Шаблон компонента --> <div class="card-shadow"> <ng-content select="card-title">Default Title</ng-content> <div class="card-divider"></div> <ng-content select="card-body">Default Body</ng-content> </div>
<!-- Использование компонента --> <custom-card> <card-title>Hello</card-title> <!-- No card-body provided --> </custom-card>
<!-- Генерация DOM --> <custom-card> <div class="card-shadow"> Hello <div class="card-divider"></div> Default Body </div> </custom-card>
Именование контента для проецирования
Angular поддерживает специальный атрибут ngProjectAs
, который указать вам на CSS-селектор для любого элемента. Каким бы ни был элемент с указанным атрибутом ngProjectAs
для передачи в <ng-content>
, Angular сравнит значение атрибута select
со значением ngProjectAs
, а не будет пытаться идентифицировать элемент через тег.
<!-- Шаблон компонента --> <div class="card-shadow"> <ng-content select="card-title"></ng-content> <div class="card-divider"></div> <ng-content></ng-content> </div>
<!-- Использование компонента --> <custom-card> <h3 ngProjectAs="card-title">Hello</h3> <p>Welcome to the example</p> </custom-card>
<!-- Генерация DOM --> <custom-card> <div class="card-shadow"> <h3>Hello</h3> <div class="card-divider"></div> <p>Welcome to the example></p> </div> </custom-card>
ngProjectAs
поддерживает только статические значения и не может принимать динамические выражения.
ссылка на оригинал статьи https://habr.com/ru/articles/873074/
Добавить комментарий