此刻,HeroesComponent 同时显示了英雄列表和所选英雄的详情。

把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。 你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。

本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 HeroDetailComponent

HeroesComponent 将仅仅用来表示英雄列表。 HeroDetailComponent 将用来表示所选英雄的详情。

你可以访问下面的链接 https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail 从 GitHub 上查看我们提供源代码。

制作 HeroDetailComponent

使用 Angular CLI 生成一个名叫 hero-detail 的新组件。

ng generate component hero-detail

这个命令会做这些事:

  • 创建一个目录 src/app/hero-detail.

在这个目录中会生成四个文件:

  • 作为组件样式的 CSS 文件。
  • 作为组件模板的 HTML 文件。
  • 存放组件类 HeroDetailComponent 的 TypeScript 文件。
  • HeroDetailComponent 类的测试文件。

该命令还会把 HeroDetailComponent 添加到 src/app/app.module.ts 文件中 @NgModule 的 declarations 列表中。

编写模板

从 HeroesComponent 模板的底部把表示英雄详情的 HTML 代码剪切粘贴到所生成的 HeroDetailComponent 模板中。

所粘贴的 HTML 引用了 selectedHero。 新的 HeroDetailComponent 可以展示任意英雄,而不仅仅所选的。因此还要把模板中的所有 selectedHero 替换为 hero

完工之后,HeroDetailComponent 的模板应该是这样的:

src/app/hero-detail/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>

添加 @Input() hero 属性

HeroDetailComponent 模板中绑定了组件中的 hero 属性,它的类型是 Hero

打开 HeroDetailComponent 类文件,并导入 Hero 符号。

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

hero 属性必须是一个带有 @Input() 装饰器的输入属性,因为外部的 HeroesComponent 组件将会绑定到它。就像这样:

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

修改 @angular/core 的导入语句,导入 Input 符号。

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

添加一个带有 @Input() 装饰器的 hero 属性。

@Input() hero: Hero;
这就是你要对 HeroDetailComponent 类做的唯一一项修改。 没有其它属性,也没有展示逻辑。这个组件所做的只是通过 hero 属性接收一个英雄对象,并显示它。

显示 HeroDetailComponent

HeroesComponent 仍然是主从视图。

在你从模板中剪切走代码之前,它自己负责显示英雄的详情。现在它要把这个职责委托给 HeroDetailComponent 了。

这两个组件将会具有父子关系。 当用户从列表中选择了某个英雄时,父组件 HeroesComponent 将通过把要显示的新英雄发送给子组件 HeroDetailComponent,来控制子组件。

你不用修改 HeroesComponent ,但是要修改它的模板

修改 HeroesComponent 的模板

HeroDetailComponent 的选择器是 'app-hero-detail'。 把 <app-hero-detail> 添加到 HeroesComponent 模板的底部,以便把英雄详情的视图显示到那里。

把 HeroesComponent.selectedHero 绑定到该元素的 hero 属性,就像这样:

heroes.component.html (HeroDetail binding)
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

[hero]="selectedHero" 是 Angular 的属性绑定语法。

这是一种单向数据绑定。从 HeroesComponent 的 selectedHero 属性绑定到目标元素的 hero 属性,并映射到了 HeroDetailComponent 的 hero 属性。

现在,当用户在列表中点击某个英雄时,selectedHero 就改变了。 当 selectedHero 改变时,属性绑定会修改 HeroDetailComponent 的 hero 属性,HeroDetailComponent 就会显示这个新的英雄。

修改后的 HeroesComponent 的模板是这样的:

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>
浏览器刷新,应用又像以前一样开始工作了。

修改了什么?

以前一样,一旦用户点击了一个英雄的名字,该英雄的详情就显示在了英雄列表下方。 现在,HeroDetailComponent 负责显示那些详情,而不再是 HeroesComponent

把原来的 HeroesComponent 重构成两个组件带来了一些优点,无论是现在还是未来:

  1. 你通过缩减 HeroesComponent 的职责简化了该组件。
  2. 你可以把 HeroDetailComponent 改进成一个功能丰富的英雄编辑器,而不用改动父组件 HeroesComponent
  3. 你可以改进 HeroesComponent,而不用改动英雄详情视图。
  4. 将来你可以在其它组件的模板中重复使用 HeroDetailComponent

查看最终代码

你的应用应该变成了这样 在线例子 / 下载范例。本页所提及的代码文件如下:

如果你想直接在 stackblitz 运行本页中的例子,请单击链接:https://stackblitz.com/github/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail

本页中所提及的代码如下:https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail

对应的文件列表和代码链接如下:

小结

  • 你创建了一个独立的、可复用的 HeroDetailComponent 组件。
  • 你用属性绑定语法来让父组件 HeroesComponent 可以控制子组件 HeroDetailComponent
  • 你用 @Input 装饰器来让 hero 属性可以在外部的 HeroesComponent 中绑定。

https://www.cwiki.us/pages/viewpage.action?pageId=47841998

Angular 主从组件的更多相关文章

  1. angular学习—组件

    组件: vue组件:xxx.vue react组件:xxx.js+xxx.css angular组件:xxx.ts+xxx.css+xxx.html angular的装饰器: @ngModule:an ...

  2. Angular 父子组件传值

    Angular 父子组件传值 @Input  @Output  @ViewChild 新建一个头部组件 newsheader 在主组件引用 news 组件,在news组件添加 newsheader 组 ...

  3. Angular 动态组件

    Angular 动态组件 实现步骤 Directive HostComponent 动态组件 AdService 配置AppModule 需要了解的概念 Directive 我们需要一个Directi ...

  4. 2021 年最值得推荐的 7 个 Angular 前端组件库 - DevUI

    摘要:DevUI 是一款面向企业中后台产品的开源前端解决方案,它倡导沉浸.灵活.至简的设计价值观,提倡设计者为真实的需求服务,为多数人的设计,拒绝哗众取宠.取悦眼球的设计.如果你正在开发 ToB 的工 ...

  5. 后端学 Angular 2 —— 组件间通信

    1. 父组件向子组件传递信息 使用@Input 子组件的属性用 @Input 进行修饰,在父组件的模板中绑定变量 例子: import { Component, OnInit, Input } fro ...

  6. angular smart-table组件如何定制化之初步研究

    table表运用在后台管理用得频繁,一般bootstrap的class="table"就能满足样式需求以及分页需求,但是每个产品经理需求不一样,比如说分页:bootstrap分页实 ...

  7. Angular自定义组件实现数据双向数据绑定

    学过Angular的同学都知道,输入框通过[(ngModel)]实现双向数据绑定,那么自定义组件能不能实现双向数据绑定呢?答案是肯定的. Angular中,我们常常需要通过方括号[]和圆括号()实现组 ...

  8. Angular 向组件传递模板的几种方法

    最近在写一个日期选择器组件,为了满足将来可能出现的各种需求,所以需要能够高度的自定义组件的样式.为了达到这个目的,需要能够在日期选择器组件外控制每个日期格子内要显示的内容,比如,标上节假日之类的.这时 ...

  9. Angular 创建组件

    创建组件 0 命令创建 1 创建组件 定义hello.component.ts组件 在app.module.ts中引用并添加到declarations声明中 在app.component.html中使 ...

随机推荐

  1. Elasticsearch Metric聚合

    首先查看index文档信息 $ curl -XGET "http://172.16.101.55:9200/_cat/indices?v" 输出 health status ind ...

  2. TCP/IP 物理层卷三 -- 传输介质

    一.有线传输介质(Guided Transmission Media)  1.1 双绞线(Twisted Pair) 双绞线(twisted pair)是一种综合布线工程中最常用的有线传输介质(导向传 ...

  3. P2670 【扫雷游戏】

    题面哦~~ lalala~~~ 这题数据并不大,最大不过100*100,所以果断穷举 其实本来我是想边读边做的,但读入是个问题. 主要思路呢,就是读完之后穷举一边,只要是炸弹,就把周围一圈8个加一遍 ...

  4. codeforces 620C

    题目链接:https://codeforces.com/problemset/problem/620/C 题目分析 题意:给你一串珍珠,每个珍珠都有一个对应值,需要分割这n个珍珠(必须连续),使得每一 ...

  5. Known Notation括号匹配类问题(2014年ACM/ICPC 亚洲区域赛牡丹江)

    题意: 给你数字或 * 的串,你可以交换一个*和数字.在最前面添1.在一个地方插入*,问你使串满足入栈出栈的(RNP)运算法则. 思路: 引用:https://blog.csdn.net/u01158 ...

  6. 关于VUE 配置文件config详解内容

    // const path = require('path'); module.exports = { /** 区分打包环境与开发环境 * process.env.NODE_ENV==='produc ...

  7. 前端之BOM,DOM

    前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些交互,我们需要继续学习BOM和DO ...

  8. springboot(十六)-swagger2

    SpringBoot整合Swagger2 相信各位在公司写API文档数量应该不少,当然如果你还处在自己一个人开发前后台的年代,当我没说,如今为了前后台更好的对接,还是为了以后交接方便,都有要求写API ...

  9. 请手写代码实现一个promise

    第一步:promise的声明 class Promise{ // 构造器 constructor(executor){ // 成功 let resolve = () => { }; // 失败 ...

  10. 禁止antd Input.Password浏览器自动回传

    设置autoComplete为new-password