Проецирование контента через ng-content

от автора

Перевод статьи с официального сайта документации 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *