AngularDart4.0 英雄之旅-教程-05多组件

耗尽温柔 提交于 2019-11-29 00:14:17

 

AppComponent正在做所有的事情。 一开始,它展示了一个英雄的细节。 然后,它成为一个英雄和英雄细节列表的主/细节形式。 很快就会有新的要求和能力。 您不能在一个组件之上填充所有功能; 这是不可维护的。

您需要将其分解为子组件,每个子组件都专注于特定的任务或工作流程。 最终,AppComponent可以成为托管这些子组件的简单shell

在这个页面中,您将通过将英雄细节划分为单独的,可重用的组件来迈向这个方向的第一步。 当你完成后,应用程序应该看起来像这样。

从哪里开始

在开始使用本页面之前,请确认您之前在“Tour of Heroes”中拥有以下结构。 如果没有,请返回前面的页面。

如果还没运行,请启动应用,保持应用处于运行状态

创建英雄详情组件

创建文件:hero_detail_component.dart,这个文件将控制新组件HeroDetailComponent

Angular 约定

  • 组件类名称使用驼峰命名法并以“Component”结尾,例:HeroDetailComponent
  • 组件文件的名称使用Snake Case命名法-单词小写且使用下划线分割以_component结束,例:hero_detail_component.dart
  • 内部实现文件应该放在lib / src下。 有关详细信息,请参阅pub package布局约定。

编写HeroDetailComponent文件:lib/src/hero_detail_component.dart (initial version)

import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';

@Component(
  selector: 'hero-detail',
  directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
}

创建一个组件,一定要引入主Angular 库。

@Component注解提供组件的Angular元数据。 CSS选择器名称hero-detail将与在父组件的模板中标识该组件的元素标签相匹配。 在本教程页面结尾处,您将向AppComponent模板添加一个<hero-detail>元素。

Hero详情模板

要将英雄细节视图移动到HeroDetailComponent,请从AppComponent模板的底部切割英雄细节内容,并将其粘贴到@Component注解的新模板参数中。

HeroDetailComponent有一个英雄,而不是一个选定的英雄。 在模板中的任何地方用单词“hero”替换“selectedHero”。 完成后,新模板应该如下所示:lib/src/hero_detail_component.dart (template)

template: '''
  <div *ngIf="hero != null">
    <h2>{{hero.name}} details!</h2>
    <div><label>id: </label>{{hero.id}}</div>
    <div>
      <label>name: </label>
      <input [(ngModel)]="hero.name" placeholder="name">
    </div>
  </div>''',

添加英雄属性

HeroDetailComponent模板绑定到组件的英雄属性。 将该属性与必要的导入一起添加到HeroDetailComponent类中。lib/src/hero_detail_component.dart (hero)

import 'hero.dart';

class HeroDetailComponent {
  Hero hero;
}

英雄属性是一个输入属性

在此页面的后面,父AppComponent将通过将其selectedHero绑定到HeroDetailComponenthero属性来通知子HeroDetailComponent显示哪个英雄。 绑定将如下所示:

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

在等号(=)左侧的英雄属性周围放置方括号使其成为属性绑定表达式的目标。 您必须将目标绑定属性声明为输入属性。 否则,Angular拒绝绑定并抛出一个错误。

声明这个hero是一个输入属性,用@Input()注释它:lib/src/hero_detail_component.dart (Input annotation)

@Input()
Hero hero;

属性指令页面中了解有关输入属性的更多信息。

hero属性是HeroDetailComponent类中唯一的东西。 它所做的就是通过其hero输入属性接收一个hero对象,然后绑定该属性到模板上。 这是完整的HeroDetailComponent

lib/src/hero_detail_component.dart

import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
import 'hero.dart';
@Component(
  selector: 'hero-detail',
  template: '''
    <div *ngIf="hero != null">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name">
      </div>
    </div>''',
  directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
  @Input()
  Hero hero;
}

HeroDetailComponent添加到AppComponent

AppComponent仍然是主/明细视图。 它用于在切出模板部分之前显示英雄细节。 现在它将委托给HeroDetailComponent

首先导入HeroDetailComponent,以便AppComponent可以引用它

import 'src/hero_detail_component.dart';

回想一下,hero-detailHeroDetailComponent元数据中的CSS选择器。 这是代表HeroDetailComponent的元素的标签名称。

AppComponent模板的底部附近添加一个<hero-detail>元素,英雄细节视图。

通过将AppComponentselectedHero属性绑定到HeroDetailComponenthero属性来将主AppComponentHeroDetailComponent进行协调。

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

现在每当selectedHero改变时,HeroDetailComponent就会得到一个新的hero显示。

修改后的AppComponent模板应该如下所示:lib/app_component.html

<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
      [class.selected]="hero === selectedHero"
      (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>
<hero-detail [hero]="selectedHero"></hero-detail>

每次用户选择一个新的英雄时,细节应该更新。 这还没有发生! 点击一个英雄。 没有细节。 如果您在浏览器开发工具的控制台中查找错误。 没有错误。

就好像Angular忽略了新的标签。 那是因为它忽略了新的标签。

指令列表

浏览器会忽略不能识别的HTML标签和属性。 Angular也是如此。

你已经导入了HeroDetailComponent,并且你已经在模板中使用了<hero-detail>,但是你还没有将它告诉给Angular。

就像您为内建的Angular指令所做的那样,通过将其列在元数据指令列表中,告诉Angular关于英雄详细信息组件。 你不需要formDirectives,所以删除它,并在文件顶部的angular_forms导入:lib/app_component.dart (directives)

directives: const [CORE_DIRECTIVES, HeroDetailComponent],

刷新浏览器。 该应用程序工作!

应用程序设计更改

和以前一样,每当用户点击一个英雄名字时,英雄详情就会出现在英雄列表的下方。 但是现在HeroDetailComponent正在呈现这些细节。

将原始AppComponent重构为两个组件,现在和将来都会带来好处:

  1. 您通过减少其职责简化了AppComponent
  2. 您可以将HeroDetailComponent演变成一个丰富的英雄编辑器,而无需触摸父AppComponent
  3. 你可以在不触及英雄详情视图的情况下演化AppComponent
  4. 您可以在将来的某个父组件的模板中重用HeroDetailComponent

查看应用程序结构

确认您具有以下结构:

这里是本页讨论的代码文件

lib/src/hero_detail_component.dart

import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
import 'hero.dart';
@Component(
  selector: 'hero-detail',
  template: '''
    <div *ngIf="hero != null">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name">
      </div>
    </div>''',
  directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
  @Input()
  Hero hero;
}

lib/app_component.dart 

import 'package:angular/angular.dart';
import 'src/hero.dart';
import 'src/hero_detail_component.dart';
import 'src/mock_heroes.dart';
@Component(
  selector: 'my-app',
  templateUrl: 'app_component.html',
  styleUrls: const ['app_component.css'],
  directives: const [CORE_DIRECTIVES, HeroDetailComponent],
)
class AppComponent {
  final title = 'Tour of Heroes';
  List<Hero> heroes = mockHeroes;
  Hero selectedHero;
  void onSelect(Hero hero) => selectedHero = hero;
}

lib/app_component.html

<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
      [class.selected]="hero === selectedHero"
      (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>
<hero-detail [hero]="selectedHero"></hero-detail>

你走过的路


以下是您在此页面中所取得的成果:

  • 您创建了一个可重用的组件。
  • 您学习了如何使组件接受输入。
  • 您学会了在 directives列表中声明应用程序指令。
  • 您学会了将父组件绑定到子组件。

你的应用应该看起来像这个实例(查看源代码)。

前方的路

“The Tour of Heroes ”游戏的应用程序可以更多地使用共享组件,但其(模拟)数据仍然是在AppComponent中硬编码的。 这是不可持续的。 数据访问应重构为单独的服务,并在需要数据的组件之间共享。

您将学习在下一个教程页面中创建服务。

下一节

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!