Перейти к содержанию

Создайте компонент характеристик

На данный момент компонент HeroesComponent отображает как список героев, так и подробную информацию о выбранном герое.

Держать все функции в одном компоненте по мере роста приложения будет невозможно. В этом руководстве крупные компоненты разбиваются на более мелкие подкомпоненты, каждый из которых ориентирован на выполнение определенной задачи или рабочего процесса.

Первым шагом будет перемещение деталей героя в отдельный, многократно используемый HeroDetailComponent, и в итоге мы получим:

  • HeroesComponent, который представляет список героев.
  • Компонент HeroDetailComponent, который представляет детали выбранного героя.

Пример приложения, которое описывается на этой странице, см.:

Создайте компонент HeroDetailComponent

Используйте эту команду ng generate для создания нового компонента с именем hero-detail.

1
ng generate component hero-detail

Команда выполняет следующее:

  • Создает каталог src/app/hero-detail.

Внутри этого каталога создаются четыре файла:

  • CSS-файл для стилей компонента.
  • HTML-файл для шаблона компонента.
  • TypeScript-файл с классом компонента с именем HeroDetailComponent.
  • Тестовый файл для класса HeroDetailComponent.

Команда также добавляет HeroDetailComponent в качестве объявления в декораторе @NgModule файла src/app/app.module.ts.

Написать шаблон

Вырежьте HTML для детализации героя из нижней части шаблона HeroesComponent и вставьте его поверх содержимого шаблона в шаблоне HeroDetailComponent.

Вставленный HTML ссылается на selectedHero. Новый HeroDetailComponent может представлять любого героя, а не только выбранного.

Замените selectedHero на hero везде в шаблоне.

Когда вы закончите, шаблон HeroDetailComponent должен выглядеть следующим образом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<div *ngIf="hero">
    <h2>{{hero.name | uppercase}} Details</h2>
    <div><span>id: </span>{{hero.id}}</div>
    <div>
        <label for="hero-name">Hero name: </label>
        <input
            id="hero-name"
            [(ngModel)]="hero.name"
            placeholder="name"
        />
    </div>
</div>

Добавьте свойство @Input() героя

Шаблон HeroDetailComponent привязывается к свойству hero компонента, которое имеет тип Hero.

Откройте файл класса HeroDetailComponent и импортируйте символ Hero.

1
import { Hero } from '../hero';

Свойство hero должно быть свойством Input, аннотированным с помощью декоратора @Input(), поскольку внешний HeroesComponent привязывается к нему следующим образом.

1
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

Измените оператор импорта @angular/core, чтобы включить символ Input.

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

Добавьте свойство hero, которому предшествует декоратор @Input().

1
@Input() hero?: Hero;

Это единственное изменение, которое вы должны внести в класс HeroDetailComponent. Больше нет никаких свойств. Нет никакой логики представления.

Этот компонент только получает объект героя через свойство hero и отображает его.

Показать HeroDetailComponent

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

Эти два компонента находятся в отношениях родитель/потомок. Родительский компонент, HeroesComponent, управляет дочерним компонентом HeroDetailComponent путем

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

Вам не нужно изменять класс HeroesComponent, вместо этого измените его шаблон.

Обновите шаблон HeroesComponent

Селектором HeroDetailComponent является 'app-hero-detail'. Добавьте элемент <app-hero-detail> в нижней части шаблона HeroesComponent, там, где раньше находилось детальное представление героя.

Привяжите HeroesComponent.selectedHero к свойству hero элемента следующим образом.

1
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

[hero]="selectedHero" — это привязка свойства Angular.

Это односторонняя привязка данных от свойства selectedHero компонента HeroesComponent к свойству hero целевого элемента, которое отображается на свойство hero компонента HeroDetailComponent.

Теперь, когда пользователь нажимает на героя в списке, selectedHero изменяется. Когда selectedHero изменяется, привязка свойств обновляет hero и

компонент HeroDetailComponent отображает нового героя.

Переработанный шаблон HeroesComponent должен выглядеть следующим образом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<h2>My Heroes</h2>

<ul class="heroes">
    <li *ngFor="let hero of heroes">
        <button
            [class.selected]="hero === selectedHero"
            type="button"
            (click)="onSelect(hero)"
        >
            <span class="badge">{{hero.id}}</span>
            <span class="name">{{hero.name}}</span>
        </button>
    </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

Браузер обновляется, и приложение начинает работать, как и раньше.

Что изменилось?

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

Теперь HeroDetailComponent представляет эти детали вместо HeroesComponent.

Рефакторинг оригинального HeroesComponent на два компонента дает преимущества, как сейчас, так и в будущем:

  1. Вы сократили обязанности HeroesComponent.
  2. Вы можете развивать HeroDetailComponent в богатый редактор героев не трогая родительский HeroesComponent.
  3. Вы можете развивать HeroesComponent, не трогая детальное представление героя.
  4. Вы можете повторно использовать HeroDetailComponent в шаблоне будущего компонента.

Окончательный обзор кода

Вот файлы кода, рассмотренные на этой странице.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { Component, Input } from '@angular/core';
import { Hero } from '../hero';

@Component({
    selector: 'app-hero-detail',
    templateUrl: './hero-detail.component.html',
    styleUrls: ['./hero-detail.component.css'],
})
export class HeroDetailComponent {
    @Input() hero?: Hero;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<div *ngIf="hero">
    <h2>{{hero.name | uppercase}} Details</h2>
    <div><span>id: </span>{{hero.id}}</div>
    <div>
        <label for="hero-name">Hero name: </label>
        <input
            id="hero-name"
            [(ngModel)]="hero.name"
            placeholder="name"
        />
    </div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<h2>My Heroes</h2>

<ul class="heroes">
    <li *ngFor="let hero of heroes">
        <button
            [class.selected]="hero === selectedHero"
            type="button"
            (click)="onSelect(hero)"
        >
            <span class="badge">{{hero.id}}</span>
            <span class="name">{{hero.name}}</span>
        </button>
    </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';

@NgModule({
    declarations: [
        AppComponent,
        HeroesComponent,
        HeroDetailComponent,
    ],
    imports: [BrowserModule, FormsModule],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

Резюме

  • Вы создали отдельный, многократно используемый HeroDetailComponent.
  • Вы использовали связывание свойств, чтобы дать родительскому HeroesComponent контроль над дочерним HeroDetailComponent.
  • Вы использовали декоратор @Input

чтобы сделать свойство hero доступным для привязки внешним HeroesComponent.

Ссылки

Комментарии