Avatar ·

@Directive и @Component в Angular: в чем разница и когда что использовать?

Всем привет! Я начал изучать Angular и TypeScript, и при создании своих первых компонентов и директив я запутался в разнице между декораторами `@Component` и `@Directive`. В документации написано, что `@Component` — это подкласс `@Directive`, но на практике они используются по-разному. Например, я создаю простую кнопку, которая меняет цвет при наведении. Я могу сделать это и через компонент, и через директиву. Вот мой код: **Вариант с @Component:** ```typescript import { Component } from '@angular/core'; @Component({ selector: 'app-hover-button', template: ``, styles: [` .highlight { background-color: yellow; } `] }) export class HoverButtonComponent { onHover() { /* добавить класс */ } onLeave() { /* убрать класс */ } } ``` **Вариант с @Directive:** ```typescript import { Directive, HostListener, HostBinding } from '@angular/core'; @Directive({ selector: '[appHoverHighlight]' }) export class HoverHighlightDirective { @HostBinding('style.backgroundColor') bgColor: string = 'transparent'; @HostListener('mouseenter') onHover() { this.bgColor = 'yellow'; } @HostListener('mouseleave') onLeave() { this.bgColor = 'transparent'; } } ``` Оба варианта работают! Но я не понимаю, когда нужно использовать `@Component`, а когда — `@Directive`. В чем их принципиальное отличие? Почему в Angular вообще два разных декоратора, если `@Component` наследуется от `@Directive`? Какой подход лучше для моего примера и почему? Объясните, пожалуйста, на понятных примерах с TypeScript. Заранее спасибо! <<>>

Главное отличие: @Component — это компонент с шаблоном, @Directive — это поведение без шаблона

Вы абсолютно правы: @Component наследуется от @Directive. Но ключевое различие — наличие шаблона (template). Компонент — это директива с собственным HTML-шаблоном, а обычная директива — это "поведение", которое вы применяете к существующему элементу.

Давайте разберем на вашем примере. У вас есть два подхода:

  • Компонент — создает новый элемент DOM (например, <app-hover-button>) с собственной разметкой и стилями.
  • Директива — изменяет поведение существующего элемента, к которому ее применяют (например, <button appHoverHighlight>).

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

Используйте @Component, когда вам нужно создать новую, самодостаточную единицу интерфейса с собственной версткой. Примеры:

  • Форма входа
  • Карточка товара
  • Модальное окно
  • Страница профиля

Пример правильного использования компонента:

@Component({
  selector: 'app-user-card',
  template: `
    <div class="card">
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
      <button (click)="editUser()">Редактировать</button>
    </div>
  `,
  styles: [`.card { border: 1px solid #ccc; padding: 10px; }`]
})
export class UserCardComponent {
  @Input() user: User;
  
  editUser() { /* логика редактирования */ }
}

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

Используйте @Directive, когда вам нужно добавить поведение к уже существующему элементу (кнопке, input, div). Директивы отлично подходят для:

  • Изменения стилей при наведении (как в вашем примере)
  • Валидации форм
  • Обработки кликов/событий
  • Манипуляции с DOM

Ваш пример с директивой — идеальный случай:

@Directive({
  selector: '[appHoverHighlight]'
})
export class HoverHighlightDirective {
  @HostBinding('style.backgroundColor') bgColor: string = 'transparent';
  
  @HostListener('mouseenter') onHover() {
    this.bgColor = 'yellow';
  }
  
  @HostListener('mouseleave') onLeave() {
    this.bgColor = 'transparent';
  }
}

// Использование в шаблоне:
// <button appHoverHighlight>Наведи на меня</button>
// <div appHoverHighlight>Или на этот блок</div>

Почему @Component — это подкласс @Directive?

В архитектуре Angular @Component расширяет @Directive для наследования общей функциональности: lifecycle hooks, dependency injection, host bindings/listeners. Но компонент добавляет:

  • template (или templateUrl) — HTML-шаблон
  • styles (или styleUrls) — изолированные стили
  • changeDetection — стратегия обнаружения изменений
  • viewProviders — провайдеры для view-детей

Итоговая рекомендация для вашего примера

Для изменения цвета кнопки при наведении используйте @Directive. Почему?

  1. Вы не создаете новый элемент — просто модифицируете существующую кнопку
  2. Директиву можно применить к любому элементу (кнопка, div, span)
  3. Код получается более переиспользуемым и легким
  4. Не нужно создавать лишнюю обертку в DOM

Запомните простое правило: если у вас есть собственный HTML-шаблон — это @Component. Если вы только добавляете поведение к существующему элементу — это @Directive.

<<>>

Дополнительный взгляд: структурные и атрибутивные директивы

Коллега выше верно описал основное отличие, но стоит добавить, что директивы делятся на два типа, и это тоже помогает понять разницу с компонентами.

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

Компонент же — это всегда элемент с собственным шаблоном. Он ближе к структурной директиве, но с полноценной версткой.

Практический совет

Если вы сомневаетесь, задайте себе вопрос: "Могу ли я применить эту логику к любому HTML-элементу без изменения его внутренней структуры?" Если да — это директива. Если вам нужно создать новый элемент с уникальной разметкой — это компонент.

Также помните: компонент может использовать директивы внутри своего шаблона. Например, ваш компонент HoverButtonComponent мог бы внутри себя применить директиву appHoverHighlight к своей кнопке. Это демонстрирует их иерархию и разделение ответственности.