Как стать автором
Обновить

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

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров177
Автор оригинала: angular.dev

Перевод статьи с официального сайта документации 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 поддерживает только статические значения и не может принимать динамические выражения.

Теги:
Хабы:
0
Комментарии0

Публикации

Истории

Работа

Ближайшие события