Angular2.x-主/细节组件
此刻,HeroesComponent
显示heroes列表和所选heroes的详细信息。
随着应用程序的增长保持一个组件中的所有功能将不可维护。您需要将大型组件分成更小的子组件,每个组件都专注于特定的任务或工作流程。
在此页面中,您将通过将heroes详细信息移动到单独的可重复使用的位置来朝此方向迈出第一步HeroDetailsComponent
。
该HeroesComponent
会目前唯一的heroes名单。该HeroDetailsComponent
会提出一个选择heroes的细节。
9.X-使HeroDetailComponent
使用Angular CLI生成一个名为的新组件hero-detail(组件一般在app目录下生产)
。
ng generate component hero-detail
该命令脚手架HeroDetailComponent
文件并声明组件AppModule
。
每次创建组件,都会声明到app.module.ts
9.1-编写模板
从HeroesComponent
模板底部剪下heroes细节的HTML ,并将其粘贴到模板中生成的样板上HeroDetailComponent
。
粘贴的HTML指的是一个selectedHero
。新的HeroDetailComponent
可以呈现任何heroes,而不仅仅是一个选定的heroes。因此,在模板中的任何地方都将“selectedHero”替换为“hero”。
完成后,HeroDetailComponent
模板应该如下所示:
herodetail.component.html
<div *ngIf="hero"> <h2>{{ hero.name | uppercase }} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div> <label>name: <input [(ngModel)]="hero.name" placeholder="name"/> </label> </div> </div>
9.2-添加heroes属性@Input()
该HeroDetailComponent
模板绑定到组件的hero
属性,它是类型Hero
。
打开HeroDetailComponent
类文件并导入Hero
符号。
src / app / hero-detail / hero-detail.component.ts(导入heroes)
import { Hero } from '../hero';
该hero
属性 必须是一个Input属性,用装饰器注释,因为外部将像这样绑定到它。@Input()
HeroesComponent
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
修改@angular/core
进口声明以包含Input
符号。
src / app / hero-detail / hero-detail.component.ts(导入输入)
import { Component, OnInit, Input } from '@angular/core';
添加一个hero
属性,在装饰器之前。@Input()
@Input() hero: Hero;
这是你应该对HeroDetailComponent
班上唯一的改变。没有更多的属性。没有表示逻辑。该组件仅通过其hero
属性接收heroes对象并显示它。
9.3-显示HeroDetailComponent
这HeroesComponent
仍然是主/细节视图。
它用于在切割模板的该部分之前自行显示heroes详细信息。现在它将委托给HeroDetailComponent
。
这两个组件将具有父母/子女关系。父母HeroesComponent
将HeroDetailComponent
通过发送一个新的heroes来控制孩子,以便在用户从列表中选择heroes时显示。
你不会改变HeroesComponent
班级,但你会改变它的模板。
更新HeroesComponent
模板
该HeroDetailComponent
选择是'app-hero-detail'
。<app-hero-detail>
在HeroesComponent
模板底部附近添加一个元素,其中heroes细节视图曾经是。
像这样绑定HeroesComponent.selectedHero
元素的hero
属性。
heroes.component.html(HeroDetail绑定)
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
[hero]="selectedHero"
是一个Angular 属性绑定。
这是一个单向的数据从绑定selectedHero
的属性HeroesComponent
的hero
目标元素,它映射到的财产hero
的性质HeroDetailComponent
。
现在,当用户点击列表中的heroes时,selectedHero
就会发生变化。当selectedHero
更改时,属性绑定更新hero
并HeroDetailComponent
显示新的heroes。
修改后的HeroesComponent
模板应该如下所示:
<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> <app-hero-detail [hero]="selectedHero"></app-hero-detail>
浏览器刷新并且应用程序重新开始工作,就像以前一样。
什么改变?
和以前一样,只要用户点击heroes名字,heroes详情就会出现在heroes列表下方。现在HeroDetailComponent
是呈现这些细节,而不是HeroesComponent
。
将原件重构HeroesComponent
为两个组件,现在和未来都会带来好处:
-
你
HeroesComponent
通过减少责任来简化它。 -
你可以演变
HeroDetailComponent
成一个丰富的heroes编辑器,而无需触摸父母HeroesComponent
。 -
你可以在
HeroesComponent
不触及heroes细节视图的情况下进化。 -
您可以重新使用
HeroDetailComponent
未来组件的模板。
src/app/hero-detail.component.html
<div *ngIf="hero"> <h2>{{ hero.name | uppercase }} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div> <label>name: <input [(ngModel)]="hero.name" placeholder="name"/> </label> </div> </div>
src/app/herodetail.component.ts
import { Component, OnInit, 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 implements OnInit { @Input() hero: Hero; constructor() { } ngOnInit() { } }
src/app/heroes/heroes.component.html
<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> <app-hero-detail [hero]="selectedHero"></app-hero-detail>
如果需要看出区别,源码如下:
Angualr2.x-列表
1 -------------------------------------------------------------------------- 2 //heroes.component.ts 3 4 import { Component, OnInit } from '@angular/core'; 5 import { Hero } from '../hero'; 6 import { HEROES } from '../mock-heroes'; 7 8 @Component({ 9 selector: 'app-heroes', 10 templateUrl: './heroes.component.html', 11 styleUrls: ['./heroes.component.css'] 12 }) 13 export class HeroesComponent implements OnInit { 14 15 heroes = HEROES; 16 17 selectedHero: Hero; 18 19 20 constructor() { } 21 22 ngOnInit() { 23 } 24 25 onSelect(hero: Hero): void { 26 this.selectedHero = hero; 27 } 28 } 29 30 -------------------------------------------------------------------------- 31 //heroes.component.html 32 33 <h2>My Heroes</h2> 34 <ul class="heroes"> 35 <li *ngFor="let hero of heroes" 36 [class.selected]="hero === selectedHero" 37 (click)="onSelect(hero)"> 38 <span class="badge">{{hero.id}}</span> {{hero.name}} 39 </li> 40 </ul> 41 42 <div *ngIf="selectedHero"> 43 44 <h2>{{ selectedHero.name | uppercase }} Details</h2> 45 <div><span>id: </span>{{selectedHero.id}}</div> 46 <div> 47 <label>name: 48 <input [(ngModel)]="selectedHero.name" placeholder="name"> 49 </label> 50 </div> 51 52 </div> 53 54 55 -------------------------------------------------------------------------- 56 //heroes.component.css 57 58 .selected { 59 background-color: #CFD8DC !important; 60 color: white; 61 } 62 .heroes { 63 margin: 0 0 2em 0; 64 list-style-type: none; 65 padding: 0; 66 width: 15em; 67 } 68 .heroes li { 69 cursor: pointer; 70 position: relative; 71 left: 0; 72 background-color: #EEE; 73 margin: .5em; 74 padding: .3em 0; 75 height: 1.6em; 76 border-radius: 4px; 77 } 78 .heroes li.selected:hover { 79 background-color: #BBD8DC !important; 80 color: white; 81 } 82 .heroes li:hover { 83 color: #607D8B; 84 background-color: #DDD; 85 left: .1em; 86 } 87 .heroes .text { 88 position: relative; 89 top: -3px; 90 } 91 .heroes .badge { 92 display: inline-block; 93 font-size: small; 94 color: white; 95 padding: 0.8em 0.7em 0 0.7em; 96 background-color: #607D8B; 97 line-height: 1em; 98 position: relative; 99 left: -1px; 100 top: -4px; 101 height: 1.8em; 102 margin-right: .8em; 103 border-radius: 4px 0 0 4px; 104 }
Angular2.x-子组件
1 <--! 2 hero-detail.component.ts 3 --> 4 import { Component, OnInit, Input } from '@angular/core'; 5 import { Hero } from '../hero'; 6 7 @Component({ 8 selector: 'app-hero-detail', 9 templateUrl: './hero-detail.component.html', 10 styleUrls: ['./hero-detail.component.css'] 11 }) 12 export class HeroDetailComponent implements OnInit { 13 @Input() hero: Hero; 14 15 constructor() { } 16 17 ngOnInit() { 18 } 19 20 } 21 ---------------------------------------------------------------------------------- 22 <--! 23 hero-detail.component.html 24 --> 25 <div *ngIf="hero"> 26 27 <h2>{{ hero.name | uppercase }} Details</h2> 28 <div><span>id: </span>{{hero.id}}</div> 29 <div> 30 <label>name: 31 <input [(ngModel)]="hero.name" placeholder="name"/> 32 </label> 33 </div> 34 35 </div> 36 ----------------------------------------------------------------------------------- 37 <--! 38 heroes.component.html 39 --> 40 <h2>My Heroes</h2> 41 42 <ul class="heroes"> 43 <li *ngFor="let hero of heroes" 44 [class.selected]="hero === selectedHero" 45 (click)="onSelect(hero)"> 46 <span class="badge">{{hero.id}}</span> {{hero.name}} 47 </li> 48 </ul> 49 50 <app-hero-detail [hero]="selectedHero"></app-hero-detail>
简述的话,也就是:
1. 在app下生成
ng generate component hero-detail
2.heroes.component.html复制到hero-detail.component.html(selectedHero内容全部修改为hero)
<div *ngIf="hero"> <h2>{{ hero.name | uppercase }} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div> <label>name: <input [(ngModel)]="hero.name" placeholder="name"/> </label> </div> </div>
3.在hero-detail.component.ts(导入heroes)
import { Hero } from '../hero';
4.在hero-detail.component.ts(导入输入)
import { Component, OnInit, Input } from '@angular/core';
5.添加一个hero
属性,在装饰器之前。@Input()
@Input() hero: Hero;
6.显示heroes.component.html
<app-hero-detail [hero]="selectedHero"></app-hero-detail>