Повторное использование — это один из столпов разработки программного обеспечения и важный показатель, который информирует нас, среди прочего, о качестве архитектуры модуля, компонента, системы…
Angular предлагает архитектуру, основанную на веб-компонентах, с целью повышения качества проекта, повторного использования блоков кода, модульности…
Одними из наиболее известных методов написания наших компонентов являются Cкомпозиция и параметризация. С помощью этих методов мы можем инкапсулировать блоки кода друг в друга (порождая новые компоненты) и настраивать их внешний вид и поведение в соответствии с некоторыми параметрами.
Цель этой статьи — познакомитьс менее известнымметодом, улучшающим повторное использование компонентов: проекцией.
Пример композиции
// list.component.html <h1> List of items </h1> <item *ngFor="let item of items"> </item> // item.component.html <div> <h2> {{ item.title }} </h2> <p> {{ item.text }} </p> </div>
Применяя эту технику, мы можем создавать компоненты, составляя другие.
Пример параметризации
// parameterized.component.ts
@Component({
...
})
export class ParametrizedComponent {
@Input() param1: string;
@Input() param2: boolean;
constructor() {}
}
// parameterized.component.html
<h1> {{ param1 }} </h1>
<span *ngIf="param2" class="badge badge-secondary"> New </span>
// foo.component.html
<h1> This is an example of ParameterizedComponent usage </h1>
<parametrized
[param1]="This is a title"
[param2]="true">
</parameterized>
Применяя эту технику, мы можем создавать компоненты, внешний вид и динамическое поведение которых зависит от параметров.
Улучшение возможности повторного использования: компонентная проекция
Используя предыдущие методы, нам удалось инкапсулировать небольшие блоки кода в компоненты, составить из них другие (композиция) и придать им различное поведение и внешний вид в зависимости от ряда предопределенных параметров.
Однако мы можем пойти еще дальше.
Представьте, что вы хотите создать макетс иерархией, которая может варьироваться помимо конфигураций с помощью параметров:
Мы могли бы использовать технику композиции и параметризации, хотя мы бы ограничили параметры и заставили бы нас писать компоненты и шаблоны с единственной целью, чтобы их использовали в… возможно, одном компоненте?
Давайте посмотрим, как наш шаблон может использовать проекцию для создания компонента «карточка» (с его заголовком, телом и нижним колонтитулом):
// tree.component.html <card> <card-header> Some header </card-header> <card-body> <div class="content"> <h2> Title </h2> <p> Lorem impsum... </p> <img src="awesome-foo.png"> </div> </card-body> <card-footer> With love by @rjlopez </card-footer> </card>
Чтобы сделать возможным построение этой иерархии, мы будем использовать угловой тег ‹ng-content›. Этот тег позволяет нам загружать в компонент шаблон, который находится внутри тега нашего компонента.
// card.component.html <div class="card text-center"> <ng-content select="app-card-header"></ng-content> <ng-content select="app-card-body"></ng-content> <ng-content select="app-card-footer"></ng-content> </div> // card-header.component.html <div class="card-header"> <ng-content></ng-content> </div>
В предыдущем предложении с помощью ‹ng-content› мы указываем, что компонент принимает встроенный HTML-тег. И какой тег вы принимаете? С помощью атрибута select мы информируем вас о том, что вы должны принимать теги типа ‹app-card-header›. В случае, если не будет передано какое-либо значение для «выбора», он примет все содержимое.
Выводы
Используя этот метод, мы можем создавать иерархические компоненты и меньше зависеть от других, что значительно улучшает возможность их повторного использования. В результате мы получим более гибкую архитектуру и увеличить степень повторного использования кода.