Что такое компоненты в Angular?
Компоненты в Angular — это базовые строительные блоки пользовательского интерфейса. Каждый компонент управляет частью экрана, отображает данные, реагирует на действия пользователя и взаимодействует с другими компонентами и сервисами. Компонент в Angular объединяет шаблон (HTML), логику (TypeScript) и стили (CSS/SCSS) в единое целое, позволяя создавать изолированные, переиспользуемые и модульные части интерфейса.
1. Структура компонента
Компонент — это обычный TypeScript-класс, аннотированный декоратором @Component, который сообщает Angular метаинформацию:
import { Component } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: \['./user.component.scss'\]
})
export class UserComponent {
name = 'Иван';
}
Основные элементы:
-
selector — имя HTML-тега, с помощью которого компонент вставляется в шаблон.
-
template / templateUrl — HTML-шаблон компонента.
-
styles / styleUrls — стили, применяемые к компоненту.
-
Класс компонента содержит свойства, методы, привязки, декораторы (@Input, @Output и др.).
2. Шаблон компонента
HTML-шаблон компонента может содержать:
-
Интерполяцию ({{ }}) для вывода значений.
-
Привязки данных ([property], {{property}}, [(ngModel)]).
-
Привязки событий ((click), (input)).
-
Структурные директивы (*ngIf, *ngFor).
-
Вложенные компоненты.
<h1>{{ name }}</h1>
<button (click)="changeName()">Изменить</button>
3. Стилизация
Каждый компонент по умолчанию использует View Encapsulation (инкапсуляция стилей), что означает, что его стили применяются только к его шаблону.
Три режима:
-
Emulated (по умолчанию) — Angular эмулирует Shadow DOM с помощью атрибутов (_nghost, _ngcontent).
-
None — глобальные стили.
-
ShadowDom — нативный Shadow DOM.
@Component({
encapsulation: ViewEncapsulation.Emulated,
...
})
4. Вложенные компоненты
Компоненты можно использовать как теги внутри других:
<app-user></app-user>
<app-product-card></app-product-card>
Они связаны через selector, и Angular автоматически их находит при сборке, если они объявлены в NgModule.
5. @Input() — входные параметры
Позволяет передавать данные в дочерний компонент из родительского.
@Component({
selector: 'app-user-card',
template: \`<h3>{{ user.name }}</h3>\`
})
export class UserCardComponent {
@Input() user: { name: string };
}
<app-user-card \[user\]="currentUser"></app-user-card>
6. @Output() — отправка событий наверх
Используется для передачи событий от дочернего компонента родителю через EventEmitter.
@Component({
selector: 'app-like-button',
template: \`<button (click)="like()">Like</button>\`
})
export class LikeButtonComponent {
@Output() liked = new EventEmitter<number>();
private count = 0;
like() {
this.count++;
this.liked.emit(this.count);
}
}
<app-like-button (liked)="onLiked($event)"></app-like-button>
7. Жизненный цикл компонента
Каждый компонент проходит определённые этапы жизненного цикла, которые можно обрабатывать с помощью хуков:
Хук | Описание |
---|---|
ngOnInit() | Вызывается после инициализации компонента. |
--- | --- |
ngOnChanges(changes) | Вызывается при изменении @Input свойств. |
--- | --- |
ngDoCheck() | Вызывается при каждом цикле обнаружения изменений. |
--- | --- |
ngAfterViewInit() | После инициализации представления. |
--- | --- |
ngOnDestroy() | Перед уничтожением компонента. |
--- | --- |
Пример:
export class MyComponent implements OnInit, OnDestroy {
ngOnInit() {
console.log('Component initialized');
}
ngOnDestroy() {
console.log('Component destroyed');
}
}
8. Динамические компоненты
Можно создавать компоненты в рантайме с помощью ViewContainerRef и ComponentFactoryResolver:
constructor(private viewContainer: ViewContainerRef) {}
load() {
this.viewContainer.createComponent(MyDynamicComponent);
}
С Angular 14+ рекомендуется использовать createComponent() без ComponentFactoryResolver.
9. Компоненты и модули
Чтобы использовать компонент в шаблоне, он должен быть объявлен (declarations) в одном из Angular модулей (@NgModule), и если он используется в другом модуле — экспортирован.
@NgModule({
declarations: \[UserComponent\],
exports: \[UserComponent\]
})
export class SharedModule {}
10. Связывание с формами
Компоненты можно использовать с формами через @Input()/@Output() или через ControlValueAccessor (создание кастомных элементов формы):
@Component({
selector: 'app-input',
template: \`<input \[value\]="value" (input)="onChange($event.target.value)">\`
})
export class CustomInputComponent implements ControlValueAccessor {
value: string;
onChange = (val: string) => {};
writeValue(val: string) {
this.value = val;
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {}
}
11. Компоненты и маршрутизация
В маршрутах Angular можно указывать компонент, который будет отображаться при переходе:
const routes: Routes = \[
{ path: 'profile', component: ProfileComponent }
\];
Использование в шаблоне:
<router-outlet></router-outlet>
Компонент, указанный в маршруте, будет отрисован в <router-outlet>.
12. Отложенная (Lazy) загрузка компонентов
Компоненты можно загружать по требованию с использованием маршрутизации и lazy модулей:
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
13. Сервисные компоненты
Некоторые компоненты не отображают UI, а управляют логикой (например, SnackbarComponent, ModalComponent) и создаются через сервисы:
this.dialog.open(MyModalComponent, { data: user });
14. Инкапсуляция и изоляция
Каждый компонент изолирован:
-
шаблон не влияет на родительский,
-
стили не “протекают” (если используется Emulated),
-
состояние управляется локально или через сервисы/инъекции.
15. Тестирование компонентов
Angular предоставляет инструменты для unit и integration тестов компонентов с использованием TestBed:
describe('UserComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: \[UserComponent\]
}).compileComponents();
});
});
16. Примеры использования
<!-- app.component.html -->
<h1>Главная страница</h1>
<app-user-card \[user\]="user" (selected)="onUserSelect($event)"></app-user-card>
export class AppComponent {
user = { name: 'Иван' };
onUserSelect(user) {
console.log('Выбран пользователь:', user);
}
}
@Component({
selector: 'app-user-card',
template: \`
<div (click)="select()">{{ user.name }}</div>
\`
})
export class UserCardComponent {
@Input() user: any;
@Output() selected = new EventEmitter();
select() {
this.selected.emit(this.user);
}
}