Avatar ·

В чем разница между @Directive и @Component в Angular?

Всем привет! Я только начал изучать Angular и TypeScript, и у меня возникла путаница с декораторами @Directive и @Component. Я понимаю, что оба они используются для создания каких-то "сущностей" в Angular, но не до конца понимаю, когда что применять. Например, я создал простой компонент для отображения кнопки: ```typescript import { Component } from '@angular/core'; @Component({ selector: 'app-my-button', template: `` }) export class MyButtonComponent { label = 'Нажми меня'; } ``` А потом попытался сделать то же самое через директиву: ```typescript import { Directive } from '@angular/core'; @Directive({ selector: '[appMyButton]' }) export class MyButtonDirective { // Как тут добавить шаблон и стили? } ``` Я прочитал, что `@Component` — это подкласс `@Directive`, но на практике они ведут себя по-разному. В `@Directive` нельзя использовать `template` и `styles`, а в `@Component` можно. Зачем тогда нужен `@Directive`, если `@Component` умеет всё то же самое и даже больше? Буду благодарен за развернутое объяснение с примерами, когда использовать директиву, а когда компонент. Спасибо! <<>>

Основное различие: Компонент — это Директива с шаблоном

Вы абсолютно правы: @Component — это подкласс @Directive. Это ключевой момент. Компонент наследует все возможности директивы (например, работу с @Input, @Output, хуками жизненного цикла) и добавляет одну критическую вещь — собственный шаблон (template).

Простыми словами:

  • Директива (@Directive) — это "поведение", которое вы навешиваете на существующий DOM-элемент. Она не создает новый элемент, а модифицирует или расширяет уже имеющийся.
  • Компонент (@Component) — это "новый элемент" со своей логикой, шаблоном и стилями. Вы используете его как тег в HTML (например, <app-my-button></app-my-button>).

Когда использовать @Directive?

Директивы идеальны для:

  • Изменения внешнего вида элемента (например, подсветка, скрытие, добавление CSS-классов).
  • Обработки событий на элементе (клики, наведение мыши, drag-and-drop).
  • Создания абстрактных поведений, которые можно переиспользовать на разных элементах.

Пример структурной директивы (изменяет DOM):

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appShowIfAdmin]'
})
export class ShowIfAdminDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) {}

  @Input() set appShowIfAdmin(isAdmin: boolean) {
    if (isAdmin) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }
}

// Использование в шаблоне:
// <div *appShowIfAdmin="isAdmin">Только для админов</div>

Когда использовать @Component?

Компоненты — это "кирпичики" вашего приложения. Используйте их, когда:

  • Нужен самостоятельный элемент интерфейса (кнопка, карточка, форма, модальное окно).
  • Элемент имеет собственный шаблон и стили.
  • Вы хотите создать переиспользуемый блок с четкой границей (инкапсуляция).

Пример компонента:

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-alert',
  template: `
    <div class="alert" [class.alert-danger]="type === 'error'">
      {{ message }}
      <button (click)="close.emit()">Закрыть</button>
    </div>
  `,
  styles: [`
    .alert { padding: 10px; border: 1px solid #ccc; }
    .alert-danger { background: #f8d7da; border-color: #f5c6cb; }
  `]
})
export class AlertComponent {
  @Input() message: string = '';
  @Input() type: 'info' | 'error' = 'info';
  @Output() close = new EventEmitter<void>();
}

Резюме

Запомните простое правило:

  • Если вы пишете template или templateUrl — используйте @Component.
  • Если вы только добавляете поведение к существующему элементу (меняете класс, обрабатываете события, добавляете/убираете элементы) — используйте @Directive.

Ваш пример с кнопкой — это классический случай для @Component, потому что вы создаете новый элемент интерфейса с собственным шаблоном. Директива же не может "создать" кнопку, она может только изменить уже существующую.

<<>>

Дополнение: Атрибутивные vs Структурные директивы

Стоит также различать два типа директив, которые часто путают с компонентами:

  • Атрибутивные директивы — меняют внешний вид или поведение элемента. Примеры: ngClass, ngStyle, ваша собственная appHighlight. Они работают как атрибуты.
  • Структурные директивы — меняют структуру DOM (добавляют/удаляют элементы). Примеры: *ngIf, *ngFor, ngSwitch. Они используют звездочку * в синтаксисе.

Компоненты же — это третий тип, который всегда создает новый элемент и имеет свой собственный DOM. Ни одна директива не может заменить компонент, если вам нужно создать независимый UI-блок с шаблоном.

Совет для новичков: если сомневаетесь, начинайте с @Component. Вы всегда сможете рефакторингом вынести логику в директиву, если заметите, что она используется как поведение без собственного шаблона.