Что такое директивы и какие бывают директивы в Angular?
В Angular директивы — это специальные классы с декоратором @Directive, которые позволяют расширять или изменять поведение элементов DOM в шаблоне. Они применяются к элементам через селекторы и могут управлять их внешним видом, поведением или структурой. Angular предоставляет встроенные директивы, а также позволяет создавать собственные.
1. Типы директив в Angular
Angular делит директивы на три основных типа:
1.1. Компоненты (Component)
-
Технически являются директивами с шаблоном.
-
Декоратор: @Component, основан на @Directive.
-
Имеют селектор и связанный шаблон.
Пример:
@Component({
selector: 'app-user-card',
template: \`<div>User card works!</div>\`
})
export class UserCardComponent {}
Все компоненты — это директивы с template, но не все директивы — компоненты.
1.2. Структурные директивы (Structural Directives)
-
Изменяют структуру DOM: добавляют, удаляют или повторяют элементы.
-
Синтаксис начинается со звёздочки * (синтаксический сахар).
-
Примеры: *ngIf, *ngFor, *ngSwitch.
*ngIf
Показывает элемент при выполнении условия.
<p \*ngIf="isLoggedIn">Добро пожаловать</p>
Реализация:
@Directive({ selector: '\[ngIf\]' })
export class NgIf { ... }
*ngFor
Повторяет элемент по коллекции.
<li \*ngFor="let user of users">{{ user.name }}</li>
*ngSwitch, *ngSwitchCase, *ngSwitchDefault
Работают как switch-case в шаблоне:
<div \[ngSwitch\]="role">
<p \*ngSwitchCase="'admin'">Админ</p>
<p \*ngSwitchCase="'user'">Пользователь</p>
<p \*ngSwitchDefault>Гость</p>
</div>
1.3. Атрибутные директивы (Attribute Directives)
-
Изменяют поведение или внешний вид существующего элемента.
-
Не изменяют структуру DOM.
-
Примеры: ngClass, ngStyle, кастомные директивы.
ngClass
Применяет CSS-классы:
<div \[ngClass\]="{ active: isActive, hidden: isHidden }"></div>
ngStyle
Применяет inline-стили:
<div \[ngStyle\]="{ color: isError ? 'red' : 'black' }"></div>
Кастомная директива:
@Directive({
selector: '\[appHighlight\]'
})
export class HighlightDirective {
constructor(private el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
<p appHighlight>Этот текст будет подсвечен</p>
2. Создание собственной директивы
Пример атрибутной директивы:
@Directive({
selector: '\[appRedText\]'
})
export class RedTextDirective {
constructor(private el: ElementRef) {
el.nativeElement.style.color = 'red';
}
}
<p appRedText>Красный текст</p>
Использование Renderer2 для безопасности:
constructor(private el: ElementRef, private renderer: Renderer2) {
this.renderer.setStyle(this.el.nativeElement, 'color', 'blue');
}
Добавление @Input:
@Input() appHighlight = 'yellow';
ngOnInit() {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', this.appHighlight);
}
<p \[appHighlight\]="'green'">Зелёный фон</p>
3. Особенности *-синтаксиса (syntactic sugar)
Директива *ngIf="isVisible" преобразуется Angular в следующую форму:
<ng-template \[ngIf\]="isVisible">
<p>Текст</p>
</ng-template>
То есть * — это сокращение, которое говорит Angular об использовании ng-template с директивой.
4. Инъекции зависимостей в директивах
В директивы можно внедрять:
-
ElementRef — прямой доступ к DOM-элементу.
-
Renderer2 — безопасная работа с DOM (для SSR).
-
HostListener — реакция на события.
-
HostBinding — привязка к свойствам host-элемента.
Пример с HostListener:
@Directive({
selector: '\[appHoverHighlight\]'
})
export class HoverHighlightDirective {
@HostListener('mouseenter') onMouseEnter() {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor');
}
constructor(private el: ElementRef, private renderer: Renderer2) {}
}
5. Пример структурной директивы с ViewContainerRef и TemplateRef
@Directive({
selector: '\[appUnless\]'
})
export class UnlessDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
@Input() set appUnless(condition: boolean) {
if (!condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
}
<p \*appUnless="isVisible">Показывается, когда isVisible == false</p>
6. Отличие компонентов от других директив
Характеристика | Компонент | Директива |
---|---|---|
Декоратор | @Component | @Directive |
--- | --- | --- |
Шаблон | Да (template) | Нет |
--- | --- | --- |
UI-элемент | Да | Нет |
--- | --- | --- |
Использование | <app-...> | [app-...] или *app-... |
--- | --- | --- |
7. Объявление директивы в модуле
Любую директиву необходимо объявить в declarations соответствующего модуля:
@NgModule({
declarations: \[
AppComponent,
HighlightDirective
\]
})
export class AppModule {}
Для повторного использования можно экспортировать директиву через SharedModule.
8. Часто используемые встроенные директивы
Директива | Тип | Назначение |
---|---|---|
*ngIf | Структурная | Условный рендеринг элементов |
--- | --- | --- |
*ngFor | Структурная | Итерация по коллекции |
--- | --- | --- |
*ngSwitch | Структурная | Альтернатива if-else |
--- | --- | --- |
ngClass | Атрибутная | Управление CSS-классами |
--- | --- | --- |
ngStyle | Атрибутная | Управление inline-стилями |
--- | --- | --- |
ngModel | Атрибутная | Двусторонняя привязка формы (требует FormsModule) |
--- | --- | --- |