网站首页 » 前端开发 » Angular 2 » Angular 4.x 多组件示例(Multiple Components)
上一篇:
下一篇:

Angular 4.x 多组件示例(Multiple Components)

AppComponent 为我们做了很多事件,在示例的一开始它完成了单个英雄信息的显示,接着就是多个英雄列表及对应英雄的详情信息。接下来我们将会看到新的需求及新的功能。你不可能在一个组件里完成所有东西,这维护起来会很吃力。

我需要把它们拆分成几个子组件,每一个子组件都专注一种任务或者工作流。而 AppComponent 就可以成为一个简单的壳来管理那些子组件。

在这篇文章里,你要做的第一件事就是把英雄的详情页单独出来,使它变成一个可重用的组件。

准备

老规矩,在示例开始之前你得保证你的项目可以,目录结构如下,如没不是,那么你可以回头看看之前的示例。

Angular 2 多组件示例(Multiple Components)

接着你就可以启动应用服务

ng serve --open

创建英雄组件

在app/ 目录下新建一个名为 hero-detail.component.ts 的文件。这个文件里会拥有一个 HeroDetailComponent 。

文件和组件名遵循下面的规范:

1、组件类的名称应该用驼峰式命名法,并且以Component 结尾,所以英雄详情页的组件的类名为 HeroDetailComponent 。

2、存放组件的文件命名则以破折号分开,并以 .component.ts 结尾。所以 HeroDetailComponent 这个类所在的文件名为 hero-detail.component.ts 。

hero-detail.component.ts 文件里的代码如下:

import { Component } from '@angular/core';

@Component({
  selector: 'hero-detail',
})
export class HeroDetailComponent {
}

要想定义一个组件,你必需引入 Component 。

@Component 装饰器给组件提供 Angular 元数据,CSS 样式的类名 hero-detail ,这个会匹配在父组件中定义的模板标签。

我们得暴露组件类,因为你可能会在很多地方用到它。

英雄详情模板

把英雄详情代码放到 HeroDetailComponent 元数据的 template 属性中。

HeroDetailComponent 有一个 hero ,但并不是选中的 hero 。用hero 替换模板中的所有 selectedHero 改完后的模板就像下面这样子。

hero-detail.component.html
<div *ngIf="hero">
  <h2>{{hero.name}} details!</h2>
  <div><label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="name"/>
  </div>
</div>

添加英雄属性

src/app/hero-detail.component.ts
hero: Hero;

hero 是一个 Hero 实例。Hero 还是在 app.component.ts 文件里。现在我们来把它单独出来,因为有两个组件都用到了它。把Hero 类的代码搬到一个单独的文件(hero.ts)。

export class Hero {
  id: number;
  name: string;
}

现在Hero 已经拥有了自己的家。AppComponent 和 HeroDetailComponent 需要去引入它。你可以像下面这样在 app.component.ts 和 hero-detail.component.ts 这两个文件中引入:

src/app/hero-detail.component.ts
import { Hero } from './hero';

英雄的属性是一个 input 属性

在接下来的内容中,父组件 AppComponent 会通过 selectedHero 来告诉子组件 HeroDetailComponent  需要显示哪一个英雄的详情内容。

src/app/app.component.html
<hero-detail [hero]="selectedHero"></hero-detail>

在“=”号的左边,用方括号包含 hero 属性,用来作为绑定表达式的属性。你必需得声明目标绑定属性为 input 属性,否则 Angular 会拒绝并抛出异常。

首先,像下面这样引入 @angular/core 来使用 Input 语法。

src/app/hero-detail.component.ts (excerpt)
import { Component, Input } from '@angular/core';

然后声明 hero 为 input 属性,通过 @Input 装饰器来接收。

src/app/hero-detail.component.ts (excerpt)
@Input() hero: Hero;

也就是说 HeroDetailComponent  类里只有 hero 属性。

src/src/app/hero-detail.component.ts
export class HeroDetailComponent {
  @Input() hero: Hero;
}

上面所做的都是为了通过 hero input 属性来得到一个 hero 对象用于绑定模板显示数据。下面就是 HeroDetailComponent 里的代码:

src/app/hero-detail.component.ts
import { Component, Input } from '@angular/core';
 
import { Hero } from './hero';
@Component({
  selector: 'hero-detail',
  template:'./hero-detail.component.html'
})
export class HeroDetailComponent {
  @Input() hero: Hero;
}

声明 HeroDetailComponent

在 AppModule 中声明 HeroDetailComponent 。因为所有的组件都需要在 Angular module 中。

在编辑器中打开 app.module.ts 文件,改入 HeroDetailComponent 。

src/app/app.module.ts
import { HeroDetailComponent } from './hero-detail.component';

把 HeroDetailComponent 添加到 declarations 数组中。

src/app/app.module.ts
declarations: [
  AppComponent,
  HeroDetailComponent
],

一般情况下,declarations  是一个包含应用组件、管道、指令的列表的数组。其它组件要想使用它,就得需要在module 中声明它。这个module 只是声明了两个组件:AppComponent 和 HeroDetailComponent。

向 AppComponent 添加 HeroDetailComponent

在你还没把代码单独出来的时候  AppComponent 依然还是显示详情信息的主体,显示英雄的详情。但现在就不一样了,我们通过 HeroDetailComponent 来处理。

还记得在 HeroDetailComponent 中的 hero-detail CSS 选择器吗?没错,它就是用来显示 HeroDetailComponent 的数据。

在 AppComponent 模板(app.component.html)的最下方添加 <hero-detail> 元素,用于显示英雄详情。

调整根组件 AppComponent ,把 AppComponent 的 selectedHero 属性赋值给 HeroDetailComponent 的 hero 属性。

app.component.ts (excerpt)
<hero-detail [hero]="selectedHero"></hero-detail>

现在不管 selectedHero 如何变化,HeroDetailComponent 都能拿到最新的值。

改进后的 AppComponent 模板如下:

app.component.ts (excerpt)
<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>

有什么变化?

前面,当用户点击一个英雄时,会在列表下方显示英雄详情,但现在就通过 HeroDetailView 输出那些详情。

重构原有的 AppComponent 有很多好外:

1、简化了 AppComponent 的功能。

2、你可以单独给 HeroDetailComponent 中的英雄添加更多属性。而不用改动到父组件 AppComponent。

3、你可以单独改进 AppComponent 而不会影响到详情内容。

4、你可以在以后的一些组件中再次使用 HeroDetailComponent 。

再次回顾下目录结构:

多组件目录

DEMO 源码

app.modeule.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail.component';

@NgModule({
  declarations: [
    AppComponent,
    HeroDetailComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component } from '@angular/core';

import { Hero } from './hero';

const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}
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>
hero-detail.component.ts
import { Component, Input } from '@angular/core';
import { Hero } from './hero';

@Component({
    selector: 'hero-detail',
    templateUrl: './hero-detail.component.html',
    styleUrls: ['./app.component.css']
})

export class HeroDetailComponent {
    @Input() hero: Hero;
}
hero-detail.component.html
<div *ngIf="hero">
  <h2>{{hero.name}} details!</h2>
  <div><label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="hero.name" />
  </div>
</div>
hero.ts
export class Hero {
    id: number;
    name: string;
}

收获

1、创建了一个可重用的组件。

2、学会了如何通过input 来获取数据。

3、知道了在模块(module)中该如何声明指令,在 declarations 数组中添加这个指令的。

4、学会了从父组件绑定子子组件。

本文就送你到这里,文章虽然不是翻译得很好,但也是一种小小的进步。

 

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/angular-tutorial-part3/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END