CWIKIUS
  • 首页
  • 计算科学
  • 房地产
  • 文化旅游
  • 项目和网站
    • OSSEZ 计算技术
    • USRealEstate 社区
    • 地区文化
    • CWIKI.US
    • BUG.OSSEZ.COM
    • RSS.OSSEZ.COM
Angular
Angular
Angular

Angular 服务

英雄指南的 HeroesComponent 目前获取和显示的都是模拟数据。 本节课的重构完成之后,HeroesComponent 变得更精简,并且聚焦于为它的视图提供支持。这也让它更容易使用模拟服务进行单元测试。 如果你希望从 GitHub 上查看我们提供测试的源代码,你可以访问下面的链接:https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-hero-services 为什么需要服务 组件不应该直接获取或保存数据,它们不应该了解是否在展示假数据。 它们应该聚焦于展示数据,而把数据访问的职责委托给某个服务。 本节课,你将创建一个 HeroService,应用中的所有类都可以使用它来获取英雄列表。 不要使用 new 来创建此服务,而要依靠 Angular 的依赖注入机制把它注入到 HeroesComponent 的构造函数中。 服务是在多个“互相不知道”的类之间共享信息的好办法。 你将创建一个 MessageService,并且把它注入到两个地方: HeroService 中,它会使用该服务发送消息。 MessagesComponent 中,它会显示其中的消息。 创建 HeroService 使用 Angular CLI 创建一个名叫 hero 的服务。 ng generate service hero 该命令会在src/app/hero.service.ts中生成HeroService类的骨架。HeroService类的代码如下: src/app/hero.service.ts (new service) import { Injectable } from '@angular/core'; @Injectable({   providedIn: 'root', }) export class HeroService {   constructor() { } } @Injectable() 服务 注意,这个新的服务导入了 Angular 的 Injectable 符号,并且给这个服务类添加了 @Injectable() 装饰器。 它把这个类标记为依赖注入系统的参与者之一。HeroService 类将会提供一个可注入的服务,并且它还可以拥有自己的待注入的依赖。 目前它还没有依赖,但是很快就会有了。 @Injectable() 装饰器会接受该服务的元数据对象,就像 @Component() 对组件类的作用一样。 获取英雄数据 HeroService 可以从任何地方获取数据:Web 服务、本地存储(LocalStorage)或一个模拟的数据源。 从组件中移除数据访问逻辑,意味着将来任何时候你都可以改变目前的实现方式,而不用改动任何组件。 这些组件不需要了解该服务的内部实现。 这节课中的实现仍然会提供模拟的英雄列表。 导入 Hero 和 HEROES。 import { Hero } from './hero'; import { HEROES } from './mock-heroes'; 添加一个 getHeroes 方法,让它返回模拟的英雄列表。 getHeroes(): Hero[] {   return HEROES; } 提供(provide) HeroService 在要求 Angular 把 HeroService 注入到 HeroesComponent 之前,你必须先把这个服务提供给依赖注入系统。稍后你就要这么做。 你可以通过注册提供商来做到这一点。提供商用来创建和交付服务,在这个例子中,它会对 HeroService 类进行实例化,以提供该服务。 现在,你需要确保 HeroService 已经作为该服务的提供商进行过注册。 你要用一个注入器注册它。注入器就是一个对象,负责在需要时选取和注入该提供商。 默认情况下,Angular CLI 命令 ng generate service 会通过给 @Injectable 装饰器添加元数据的形式,用根注入器将你的服务注册成为提供商。 如果你看看 HeroService 紧前面的 @Injectable() 语句定义,就会发现 providedIn 元数据的值是 'root': @Injectable({   providedIn: 'root', }) @ Injectable ({ providedIn: 'root', }) 当你在顶层提供该服务时,Angular 就会为 HeroService 创建一个单一的、共享的实例,并把它注入到任何想要它的类上。 在 @Injectable 元数据中注册该提供商,还能允许 Angular 通过移除那些完全没有用过的服务来进行优化。 要了解关于提供商的更多知识,参见提供商部分。 要了解关于注入器的更多知识,参见依赖注入指南。 现在 HeroService 已经准备好插入到 HeroesComponent 中了。 这是一个过渡性的代码范例,它将会允许你提供并使用 HeroService。此刻的代码和最终代码相差很大。 修改 HeroesComponent 打开 HeroesComponent 类文件。 删除 HEROES 的导入语句,因为你以后不会再用它了。 转而导入 HeroService。 src/app/heroes/heroes.component.ts (import HeroService) import { HeroService } from '../hero.service'; 把 heroes 属性的定义改为一句简单的声明。 heroes: Hero[]; 注入 HeroService 往构造函数中添加一个私有的 heroService,其类型为 HeroService。 constructor(private heroService: HeroService) { } 这个参数同时做了两件事:1. 声明了一个私有 heroService 属性,2. 把它标记为一个 HeroService 的注入点。 当 Angular 创建 HeroesComponent 时,依赖注入系统就会把这个 heroService 参数设置为 HeroService 的单例对象。 添加 getHeroes() 创建一个函数,以从服务中获取这些英雄数据。 getHeroes(): void {   this.heroes = this.heroService.getHeroes(); } 在 ngOnInit 中调用它 你固然可以在构造函数中调用 getHeroes(),但那不是最佳实践。 让构造函数保持简单,只做初始化操作,比如把构造函数的参数赋值给属性。 构造函数不应该做任何事。 它当然不应该调用某个函数来向远端服务(比如真实的数据服务)发起 HTTP 请求。 而是选择在 ngOnInit 生命周期钩子中调用 getHeroes(),之后交由 Angular 处理,它会在构造出 HeroesComponent 的实例之后的某个合适的时机调用 ngOnInit。 ngOnInit() {   this.getHeroes(); } 查看运行效果 刷新浏览器,该应用仍运行的一如既往。 显示英雄列表,并且当你点击某个英雄的名字时显示出英雄详情视图。 可观察(Observable)的数据 HeroService.getHeroes() 的函数签名是同步的,它所隐含的假设是 HeroService 总是能同步获取英雄列表数据。 而 HeroesComponent 也同样假设能同步取到 getHeroes() 的结果。 this.heroes = this.heroService.getHeroes(); 这在真实的应用中几乎是不可能的。 现在能这么做,只是因为目前该服务返回的是模拟数据。 不过很快,该应用就要从远端服务器获取英雄数据了,而那天生就是异步操作。 HeroService 必须等服务器给出响应, 而 getHeroes() 不能立即返回英雄数据, 浏览器也不会在该服务等待期间停止响应。 HeroService.getHeroes() 必须具有某种形式的异步函数签名。 它可以使用回调函数,可以返回 Promise(承诺),也可以返回 Observable(可观察对象)。 这节课,HeroService.getHeroes() 将会返回 Observable,因为它最终会使用 Angular 的 HttpClient.get 方法来获取英雄数据,而 HttpClient.get() 会返回 Observable。 可观察对象版本的 HeroService Observable 是 RxJS 库中的一个关键类。 在稍后的 HTTP 教程中,你就会知道 Angular HttpClient 的方法会返回 RxJS 的 Observable。 这节课,你将使用 RxJS 的 of() 函数来模拟从服务器返回数据。 打开 HeroService 文件,并从 RxJS 中导入 Observable 和 of 符号。 src/app/hero.service.ts (Observable imports) import { Observable, of } from 'rxjs'; 把 getHeroes 方法改成这样: getHeroes(): Observable<Hero[]> {   return of(HEROES); } of(HEROES)会返回一个Observable<Hero[]>,它会发出单个值,这个值就是这些模拟英雄的数组。 在 HTTP 教程中,你将会调用 HttpClient.get<Hero[]>() 它也同样返回一个 Observable<Hero[]>,它也会发出单个值,这个值就是来自 HTTP 响应体中的英雄数组。 在 HeroesComponent 中订阅 HeroService.getHeroes 方法之前返回一个 Hero[], 现在它返回的是 Observable<Hero[]>。 你必须在 HeroesComponent 中也向本服务中的这种形式看齐。 找到 getHeroes 方法,并且把它替换为如下代码(和前一个版本对比显示): heroes.component.ts (Observable) getHeroes(): void {   this.heroService.getHeroes()       .subscribe(heroes => this.heroes = heroes); } heroes.component.ts (Original) getHeroes(): void {   this.heroes = this.heroService.getHeroes(); } Observable.subscribe() 是关键的差异点。 上一个版本把英雄的数组赋值给了该组件的 heroes 属性。 这种赋值是同步的,这里包含的假设是服务器能立即返回英雄数组或者浏览器能在等待服务器响应时冻结界面。 当 HeroService 真的向远端服务器发起请求时,这种方式就行不通了。 新的版本等待 Observable 发出这个英雄数组,这可能立即发生,也可能会在几分钟之后。 然后,subscribe 函数把这个英雄数组传给这个回调函数,该函数把英雄数组赋值给组件的 heroes属性。 使用这种异步方式,当 HeroService 从远端服务器获取英雄数据时,就可以工作了。 显示消息 在这一节,你将 添加一个 MessagesComponent,它在屏幕的底部显示应用中的消息。 创建一个可注入的、全应用级别的 MessageService,用于发送要显示的消息。 把 MessageService 注入到 HeroService 中。 当 HeroService 成功获取了英雄数据时显示一条消息。 创建 MessagesComponent 使用 CLI 创建 MessagesComponent。 ng generate component messages CLI 在 src/app/messages 中创建了组件文件,并且把 MessagesComponent 声明在了 AppModule 中。 修改 AppComponent 的模板来显示所生成的 MessagesComponent: /src/app/app.component.html <h1>{{title}}</h1> <app-heroes></app-heroes> <app-messages></app-messages> 你可以在页面的底部看到来自的 MessagesComponent 的默认内容。 创建 MessageService 使用 CLI 在 src/app 中创建 MessageService。…

2019年05月30日 0Comments 526Browse 0Like Read more
Angular

Angular 主从组件

此刻,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 重构成两个组件带来了一些优点,无论是现在还是未来: 你通过缩减 HeroesComponent 的职责简化了该组件。 你可以把 HeroDetailComponent 改进成一个功能丰富的英雄编辑器,而不用改动父组件 HeroesComponent。 你可以改进 HeroesComponent,而不用改动英雄详情视图。 将来你可以在其它组件的模板中重复使用 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 对应的文件列表和代码链接如下: 文件名 源代码 src/app/hero-detail/hero-detail.component.ts https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/hero-detail/hero-detail.component.ts src/app/hero-detail/hero-detail.component.html https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/hero-detail/hero-detail.component.html src/app/heroes/heroes.component.html https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/heroes/heroes.component.html src/app/app.module.ts https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/app.module.ts 小结 你创建了一个独立的、可复用的 HeroDetailComponent 组件。 你用属性绑定语法来让父组件 HeroesComponent 可以控制子组件 HeroDetailComponent。 你用 @Input 装饰器来让 hero 属性可以在外部的 HeroesComponent 中绑定。 https://www.cwiki.us/pages/viewpage.action?pageId=47841998

2019年05月29日 0Comments 527Browse 0Like Read more
Angular

Angular 显示英雄列表

在本页面,你将扩展《英雄指南》应用,让它显示一个英雄列表, 并允许用户选择一个英雄,查看该英雄的详细信息。 创建模拟(mock)英雄数据 你需要一些英雄数据以供显示。 最终,你会从远端的数据服务器获取它。但是目前,你需要创建一些模拟英雄(some mock heroes),并假设这些数据是从远程服务器上获取的。 在 src/app/ 文件夹中创建一个名叫 mock-heroes.ts 的文件。 定义一个包含十个英雄的常量数组 HEROES,并导出它。 该文件是这样的。 src/app/mock-heroes.ts import { Hero } from './hero'; export 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' } ]; 显示英雄 你要在 HeroesComponent 的顶部显示这个英雄列表。 打开 HeroesComponent 类文件,并导入模拟的 HEROES 数据。 src/app/heroes/heroes.component.ts import { HEROES } from '../mock-heroes'; 往类中添加一个 heroes 属性,这样可以暴露出这些英雄,以供绑定。 src/app/heroes/heroes.component.ts export class HeroesComponent implements OnInit {   heroes = HEROES; 使用 *ngFor 列出这些英雄 打开 HeroesComponent 的模板文件,并做如下修改: 在顶部添加 <h2> 然后添加表示无序列表的 HTML 元素(<ul>) 在 <ul> 中插入一个 <li> 元素,以显示单个 hero 的属性。 点缀上一些 CSS 类(稍后你还会添加更多 CSS 样式)。 完成后应该如下显示: heroes.component.html heroes.component.html (heroes template) content_copy <h2>My Heroes</h2> <ul class="heroes">   <li>     <span class="badge">{{hero.id}}</span> {{hero.name}}   </li> </ul> 现在,把 <li> 修改成这样: <li *ngFor="let hero of heroes"> *ngFor 是一个 Angular 的复写器(repeater)指令。 它会为列表中的每项数据复写它的宿主元素。 在这个例子中 <li> 就是 *ngFor 的宿主元素 heroes 就是来自 HeroesComponent 类的列表。 当依次遍历这个列表时,hero 会为每个迭代保存当前的英雄对象。 不要忘了 ngFor 前面的星号(*),它是该语法中的关键部分。 浏览器刷新之后,英雄列表出现了。 给英雄们应用样式表 英雄列表应该富有吸引力,并且当用户把鼠标移到某个英雄上和从列表中选中某个英雄时,应该给出视觉反馈。 在教程的第一章,你曾在 styles.css 中为整个应用设置了一些基础的样式。 但那个样式表并不包含英雄列表所需的样式。 固然,你可以把更多样式加入到 styles.css,并且放任它随着你添加更多组件而不断膨胀。 但还有更好的方式。你可以定义属于特定组件的私有样式,并且让组件所需的一切(代码、HTML 和 CSS)都放在一起。 这种方式让你在其它地方复用该组件更加容易,并且即使全局样式和这里不一样,组件也仍然具有期望的外观。 你可以用多种方式定义私有样式,或者内联在 @Component.styles 数组中,或者在 @Component.styleUrls 所指出的样式表文件中。 当 CLI 生成 HeroesComponent 时,它也同时为 HeroesComponent 创建了空白的 heroes.component.css 样式表文件,并且让 @Component.styleUrls 指向它,就像这样: src/app/heroes/heroes.component.ts @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) 打开 heroes.component.css 文件,并且把 HeroesComponent 的私有 CSS 样式粘贴进去。 你可以在本指南底部的查看最终代码中找到它们。 @Component 元数据中指定的样式和样式表都是局限于该组件的。 heroes.component.css 中的样式只会作用于 HeroesComponent,既不会影响到组件外的 HTML,也不会影响到其它组件中的 HTML。 主从结构 当用户在主列表中点击一个英雄时,该组件应该在页面底部显示所选英雄的详情。 在本节,你将监听英雄条目的点击事件,并更新英雄的详情。 添加 click 事件绑定 再往 <li> 元素上插入一句点击事件的绑定代码: heroes.component.html <li *ngFor="let hero of heroes" (click)="onSelect(hero)"> 这是 Angular 事件绑定 语法的例子。 click 外面的圆括号会让 Angular 监听这个 <li> 元素的 click 事件。 当用户点击 <li> 时,Angular 就会执行表达式 onSelect(hero)。 onSelect() 是 HeroesComponent 上的一个方法,你很快就要写它。 Angular 会把所点击的 <li> 上的 hero 对象传给它,这个 hero 也就是前面在 *ngFor 表达式中定义的那个。 添加 click 事件处理器 把该组件的 hero 属性改名为 selectedHero,但不要为它赋值。 因为应用刚刚启动时并没有所选英雄。 添加如下 onSelect() 方法,它会把模板中被点击的英雄赋值给组件的 selectedHero 属性。 src/app/heroes/heroes.component.ts selectedHero: Hero; onSelect(hero: Hero): void {   this.selectedHero = hero; } 修改详情模板 该模板引用的仍然是老的 hero 属性,但它已经不存在了。 把 hero 改名为 selectedHero。 heroes.component.html <h2>{{selectedHero.name | uppercase}} Details</h2> <div><span>id: </span>{{selectedHero.id}}</div> <div>   <label>name:     <input [(ngModel)]="selectedHero.name" placeholder="name">   </label> </div> 刷新浏览器,应用挂了。 打开浏览器的开发者工具,它的控制台中显示出如下错误信息: HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined 出现了什么问题? 当应用启动时,selectedHero 是 undefined,设计如此。 但模板中的绑定表达式引用了 selectedHero 的属性(表达式为 {{selectedHero.name}}),这必然会失败,因为你还没选过英雄呢。 现在,从列表中随便点击一个条目。 应用又正常了。 英雄们显示在列表中,并且所点英雄的详情也显示在了页面的下方。 修复 - 使用 *ngIf 来隐藏空白的细节 该组件应该只有当 selectedHero 存在时才显示所选英雄的详情。 把显示英雄详情的 HTML 包裹在一个 <div> 中。 并且为这个 div 添加 Angular 的 *ngIf 指令,把它的值设置为 selectedHero。 不要忘了 ngIf 前面的星号(*),它是该语法中的关键部分。 src/app/heroes/heroes.component.html (*ngIf) <div *ngIf="selectedHero">   <h2>{{selectedHero.name | uppercase}} Details</h2>   <div><span>id: </span>{{selectedHero.id}}</div>   <div>     <label>name:       <input [(ngModel)]="selectedHero.name" placeholder="name">     </label>   </div> </div> 浏览器刷新之后,英雄名字的列表又出现了。 详情部分仍然是空。 点击一个英雄,它的详情就出现了。 这个应用看起来又再次工作正常显示了。 英雄显示在列表中,当你单击英雄的名字的时候,有关你单击英雄的详细信息就显示在页面的底部了。 为什么这样是正常的 当 selectedHero 为 undefined 时,ngIf 从 DOM 中移除了英雄详情。因此也就不用担心 selectedHero 的绑定了。 当用户选择一个英雄时,selectedHero 也就有了值,并且 ngIf 把英雄的详情放回到 DOM 中。 给所选英雄添加样式 所有的 <li> 元素看起来都是一样的,因此很难从列表中识别出所选英雄。 如果用户点击了“Magneta”,这个英雄应该用一个略有不同的背景色显示出来,就像这样: 所选英雄的颜色来自于你前面添加的样式中的 CSS 类 .selected。 所以你只要在用户点击一个 <li> 时把 .selected 类应用到该元素上就可以了。 Angular 的 CSS 类绑定机制让根据条件添加或移除一个 CSS 类变得很容易。 只要把 [class.some-css-class]="some-condition" 添加到你要施加样式的元素上就可以了。 在 HeroesComponent 模板中的 <li> 元素上添加 [class.selected] 绑定,代码如下: heroes.component.html (toggle the…

2019年05月29日 0Comments 517Browse 0Like Read more
Angular

Angular 英雄编辑器

应用程序现在有了基本的标题。 接下来你要创建一个新的组件来显示英雄信息并且把这个组件放到应用程序的外壳里去。 创建英雄组件 使用 Angular CLI 创建一个名为 heroes 的新组件。 ng generate component heroes CLI 创建了一个新的文件夹, src/app/heroes/,并生成了 HeroesComponent 的 4 个文件。 HeroesComponent 的类文件如下: heroes.component.ts import { Component, OnInit } from '@angular/core'; @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit {   constructor() { }   ngOnInit() {   } } 你要从 Angular 核心库中导入  Component  符号,并为组件类加上 @ Component  注解。 @Component 是一个修饰器函数,这个函数为组件指定了 Angular 元数据。 CLI 自动生成了三个元数据属性: selector — 组件的 CSS 元素选择器。 templateUrl — 组件模板文件的位置。 styleUrls — 组件私有 CSS 样式表文件的位置。 CSS 元素选择器 app-heroes 用来在父组件的模板中匹配 HTML 元素的名称,以识别出该组件。 ngOnInit 是一个生命周期钩子(lifecycle hook),Angular 在创建完组件后很快就会调用 ngOnInit。这里是放置初始化逻辑的好地方。 始终要 export 这个组件类,以便于在其它地方(比如 AppModule)导入它。 添加一个 hero 属性 往 HeroesComponent 中添加一个 hero 属性,用来表示一个名叫 “Windstorm” 的英雄。 hero = 'Windstorm'; 显示英雄 打开模板文件 heroes.component.html。删除 Angular CLI 自动生成的默认内容,改为到 hero 属性的数据绑定。 heroes.component.html {{hero}} 显示 HeroesComponent 视图 要显示 HeroesComponent 你必须把它加到壳组件 AppComponent 的模板中。 别忘了,app-heroes 就是 HeroesComponent 的 元素选择器(element selector)。 所以,只要把 <app-heroes> 元素添加到 AppComponent 的模板文件(app.component.html)中就可以了,就放在标题下方。 app.component.html <h1>{{title}}</h1> <app-heroes></app-heroes> 如果 CLI 的 ng serve 命令仍在运行,浏览器就会自动刷新,并且同时显示出应用的标题和英雄的名字。 创建一个 Hero 类 真实的英雄当然不仅仅只有一个名字。 在 src/app 文件夹中为 Hero 类创建一个文件,并添加 id 和 name 属性。 src/app/hero.ts export class Hero {   id: number;   name: string; } 回到 HeroesComponent 类,并且导入这个 Hero 类。 把组件的 hero 属性的类型重构为 Hero。 然后以 1 为 id、以 “Windstorm” 为名字初始化它。 修改后的 HeroesComponent 类应该是这样的: src/app/heroes/heroes.component.ts import {Component, OnInit} from '@angular/core'; import {Hero} from '../hero'; @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit {   hero: Hero = {     id: 1,     name: 'Windstorm'   };   constructor() {   }   ngOnInit() {   } } 页面显示变得不正常了,因为你刚刚把 hero 从字符串改成了对象。 显示 hero 对象 修改模板中的绑定,以显示英雄的名字,并在详情中显示 id 和 name,就像这样: heroes.component.html (HeroesComponent 的模板) <h2>{{hero.name}} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div><span>name: </span>{{hero.name}}</div> 浏览器自动刷新,并显示这位英雄的信息。 使用 UppercasePipe 进行格式化 把 hero.name 的绑定修改成这样: <h2>{{hero.name | uppercase}} Details</h2> 对浏览器进行刷新。现在,你会发现英雄的名字显示成了大写字母。 位于管道操作符( | )的右边的单词 uppercase 表示的是一个插值绑定,用于调用内置的 UppercasePipe。 管道(Pipes) 是格式化字符串、金额、日期和其它显示数据的好办法。 Angular 发布了一些内置管道,当然你还可以创建自己的管道。 编辑英雄 用户应该能在一个 <input> 文本输入框(textbox)中编辑英雄的名字。 当用户输入时,这个输入框应该能同时显示和修改英雄的 name 属性。 也就是说,数据流从组件类流出到屏幕,并且从屏幕流回到组件类。 要想让这种数据流动自动化,就要在表单元素 <input> 和组件的 hero.name 属性之间建立双向数据绑定。 双向绑定 把 HeroesComponent 模板中的英雄详情区重构成这样: src/app/heroes/heroes.component.html (HeroesComponent 模板) <div>   <label>name:     <input [(ngModel)]="hero.name" placeholder="name"/>   </label> </div> [(ngModel)] 是 Angular 的双向数据绑定句法。 这里把 hero.name 属性绑定到了 HTML 的 textbox 元素上,以便数据流可以双向流动:从 hero.name 属性流动到 textbox,并且从 textbox 流回到 hero.name 。 缺少 FormsModule 注意,当你加上 [(ngModel)] 之后这个应用无法工作了。 打开浏览器的开发工具,就会在控制台中看到如下信息: Uncaught Error: Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'. 虽然 ngModel 是一个有效的 Angular 指令,不过它在默认情况下是不可用的。 它属于一个可选模块 FormsModule,你必须自行添加此模块才能使用该指令。 AppModule Angular 需要知道如何把应用程序的各个部分组合到一起,以及该应用需要哪些其它文件和库。 这些信息被称为元数据(metadata)。 最重要的 @NgModule 装饰器位于顶级类 AppModule 上。 Angular CLI 在创建项目的时候就在 src/app/app.module.ts 中生成了一个 AppModule 类。 这里也就是你要添加 FormsModule 的地方。 导入 FormsModule 打开 AppModule (app.module.ts) 并从 @angular/forms 库中导入 FormsModule 符号。 app.module.ts (FormsModule 符号导入) import {FormsModule} from '@angular/forms'; 然后把 FormsModule 添加到 @NgModule 元数据的 imports 数组中,这里是该应用所需外部模块的列表。 app.module.ts(@NgModule 导入) imports: [   BrowserModule,   FormsModule ], 刷新浏览器,应用又能正常工作了。你可以编辑英雄的名字,并且会看到这个改动立刻体现在这个输入框上方的 <h2> 中。 声明 HeroesComponent 每个组件都必须声明在(且只能声明在)一个 NgModule 中。 你没有声明过 HeroesComponent,可为什么应用却正常工作呢? 这是因为 Angular CLI 在生成 HeroesComponent 组件的时候就自动把它加到了 AppModule 中。 打开 src/app/app.module.ts 你可以在顶部找到 HeroesComponent 已经被导入过了。 src/app/app.module.ts import {HeroesComponent} from './heroes/heroes.component'; HeroesComponent 也已经声明在了 @NgModule.declarations 数组中。 declarations: [   AppComponent,   HeroesComponent ], 注意:AppModule 声明了应用中的所有组件,AppComponent 和 HeroesComponent。 最终代码预览 应用跑起来应该是这样的:在线例子 / 下载范例。…

2019年05月24日 0Comments 572Browse 0Like Read more
Angular

Angular 英雄示例教程

英雄指南教程(Tour of Heroes)涵盖了 Angular 的基本知识。 在本教程中,你将构建一个应用,来帮助人事代理机构来管理一群英雄。 这个入门级 app 包含很多数据驱动的应用所需的特性。 它需要获取并显示英雄的列表、编辑所选英雄的详情,并且在包含有英雄数据的不同视图之间进行导航。 在本教程的最后,你的应用可以做下面的工作: 使用Angular 的内置指令(Angular directives)来显示 / 隐藏元素,并显示英雄数据的列表。 创建 Angular 组件(Angular components)以显示英雄的详情,并显示一个英雄数组。 为只读数据使用单向数据绑定。 添加可编辑字段,使用双向数据绑定来更新模型。 为用户事件绑定组件方法(component methods),比如相应用户键盘输入和点击。 让用户可以在主列表中选择一个英雄,然后在详情视图中编辑他。 使用管道来格式化数据。 创建共享的服务来管理这些英雄。 使用路由在不同的视图及其组件之间导航。 你将学到足够的 Angular 知识和足够的信心来让 Angular 提供你所需的支持。 完成本教程的所有步骤之后,最终的应用会是这样的:live example / download example。 你将要构建什么 下面是本教程有关界面的构想:本应用开始界面为"Dashboard(主面板)"视图,在这个视图中显示最勇敢的英雄。 你可以单击主面板上的两个链接("Dashboard" 和 "Heroes")来在主面板视图和英雄视图之间进行导航。 如果你在主面板中单击英雄名称 "Magneta" 时,路由将会打开 "Hero Details(英雄详细)"页面。在这个页面中,你可以对英雄的名字进行修改。 单击 "Back(返回按钮)",应用将会让你返回到 Dashboard(主面板)页面中。顶部的链接能够让你在任何时候都能够返回到主页面。如果你单击  "Heroes(英雄列表)",引用将会将英雄以列表显示。 当你单击不同英雄的名字的时候,一个只读的“微型详情视图”会在列表的下方显示,以体现你的选择。 你可以点击 “View Details(查看详情)” 按钮进入所选英雄的编辑视图。 下面这张图汇总了所有可能的导航选项。 下面是本应用的动态展示:   https://www.cwiki.us/display/AngularZH/Tutorial

2019年05月21日 0Comments 484Browse 0Like Read more
Angular

Angular 应用的外壳

你首先需要使用 Angular CLI 来创建一个初始化的应用。随后,你将对你已经初始化的应用进行修改来让你构建出 Tour of Heroes app(英雄指南) 这个应用。 在教程的本部分,你需要完成下面的操作: 设置的你的环境。 创建一个新的工作区(workspace)和初始化应用项目。 启动应用服务器。 对应用进行修改。 设置你的环境 希望对你的开发环境进行设置,请参考下面的链接中的指南:Getting started: 先决条件 安装 Angular CLI 你不需要按照 Getting started 页面中说明的内容从头到尾的进行一次,你只需要完成上面提示的 2 个部分就可以将环境设置好了。 继续下一步来创建《英雄指南》的工作区并且将这个应用初始化。 创建一个新工作区并且初始化应用 Angular 的工作区就是你开发应用所在的上下文环境。一个工作区包含一个或多个项目所需的文件。每个项目都是一组由应用、库或端到端(e2e)测试组成的文件集合。 在本教程中,你将创建一个新的工作区。 希望创建一个新工作区并且初始一个应用项目,你需要: 确保你现在没有位于 Angular 工作区的文件夹中。例如,在前面的教程中,你已经创建了 Getting Started workspace(开始使用工作区),请回到上级目录中。 运行 CLI 命令  ng new 然后提供空间的名字  angular-tour-of-heroes, 完整的命令如下显示: ng new angular-tour-of-heroes ng new 命令会提示你输入要在初始应用项目中包含哪些特性,请按 Enter 或 Return 键接受其默认值。 Angular CLI 会安装必要的 Angular npm 包和其它依赖项。这可能需要几分钟。 它还会创建下列工作区和初始项目的文件: 新的工作区,其根目录名叫 angular-tour-of-heroes。 一个最初的骨架应用项目,同样叫做 angular-tour-of-heroes(位于 src 子目录下)。 一个端到端测试项目(位于 e2e 子目录下)。 相关的配置文件。 初始应用项目是一个简单的 "欢迎" 应用,随时可以运行它。 启动应用服务器 进入工作区目录,并启动这个应用。 cd angular-tour-of-heroes ng serve --open ng serve 命令会构建本应用、启动开发服务器、监听源文件,并且当那些文件发生变化时重新构建本应用。 --open 标志会打开浏览器,并访问 http://localhost:4200/。 你会发现,这个应用已经启动了,并且可以通过浏览器进行访问了。 Angular 组件 你所看到的这个页面就是application shell(应用的外壳)。 这个外壳是被一个名叫 AppComponent 的 Angular 组件(component)控制的。 Components(组件)  是 Angular 应用中的基本构造块。 它们在屏幕上显示数据,监听用户输入,并且根据这些输入执行相应的动作。 对应用进行修改 用你喜欢的编辑器或 IDE 打开这个项目,并访问 src/app 目录,来对这个起始应用做一些修改。 你会在这里看到 AppComponent 外壳的三个实现文件: app.component.ts— 组件的类代码,这是用 TypeScript 写的。 app.component.html— 组件的模板,这是用 HTML 写的。 app.component.css—  组件的私有 CSS 样式。 修改应用的标题 打开组件的类文件 (app.component.ts),并把 title 属性的值修改为 'Tour of Heroes' (英雄指南)。 title = 'Tour of Heroes'; 打开组件的模板文件 app.component.html 并清空 Angular CLI 自动生成的默认模板。改为下列 HTML 内容: <h1>{{title}}</h1> 双花括号语法是 Angular 的插值绑定语法。 这个插值绑定的意思是把组件的 title 属性的值绑定到 HTML 中的 h1 标记 浏览器自动刷新,并且显示出了新的应用标题。 添加应用样式 大多数应用都会努力让整个应用保持一致的外观。 因此,CLI 会生成一个空白的 styles.css 文件。 你可以把全应用级别的样式放进去。 打开 src/styles.css 并把下列代码添加到此文件中。 /* Application-wide Styles */ h1 {   color: #369;   font-family: Arial, Helvetica, sans-serif;   font-size: 250%; } h2, h3 {   color: #444;   font-family: Arial, Helvetica, sans-serif;   font-weight: lighter; } body {   margin: 2em; } body, input[type="text"], button {   color: #888;   font-family: Cambria, Georgia; } /* everywhere else */ * {   font-family: Arial, Helvetica, sans-serif; } 查看最终代码 本教程的源文件以及英雄指南的完整全局样式可以在 在线例子 / 下载范例 中看到。 下面是本页所提到的源代码: src/app/app.component.ts import { Component } from '@angular/core'; @Component({   selector: 'app-root',   templateUrl: './app.component.html',   styleUrls: ['./app.component.css'] }) export class AppComponent {   title = 'Tour of Heroes'; } src/app/app.component.html <h1>{{title}}</h1> src/styles.css /* Application-wide Styles */ h1 {   color: #369;   font-family: Arial, Helvetica, sans-serif;   font-size: 250%; } h2, h3 {   color: #444;   font-family: Arial, Helvetica, sans-serif;   font-weight: lighter; } body {   margin: 2em; } body, input[type="text"], button {   color: #888;   font-family: Cambria, Georgia; } /* everywhere else */ * {   font-family: Arial, Helvetica, sans-serif; } 小结 你使用 Angular CLI 创建了初始的应用结构。 你学会了使用 Angular 组件来显示数据。 你使用双花括号插值表达式显示了应用标题。   https://www.cwiki.us/display/AngularZH/The+Application+Shell

2019年05月21日 0Comments 543Browse 0Like Read more
Angular

https://stackblitz.com/github/cwiki-us-angular/cwiki-us-angular-app 导入后如何添加到自己的项目

将 https://stackblitz.com/github/cwiki-us-angular/cwiki-us-angular-app 导入到界面后,如何将这个项目添加到自己的项目里面。 然后再自己的项目里面进行编辑,修改后提交? 你可以在编辑界面中 Fork 到本地后进行修改。

2019年05月17日 0Comments 522Browse 0Like Read more
Angular

如何将 GitHub 中的项目导入到 stackblitz.com 中

如何将一个 GitHub 中的项目导入到 stackblitz.com 中,然后开始编辑和编译呢? 例如,我们有一个项目在 GitHub 中的地址为:https://github.com/cwiki-us-angular/cwiki-us-angular-app 如何将这个项目导入到 stackblitz.com 中进行编辑和测试呢?   首先你需要在 stackblitz.com 中注册一个用户名和密码。 你可以可以使用你 GitHub 的用户名进行关联。 当你注册成功后,你可以访问下面的地址:https://stackblitz.com/github/cwiki-us-angular/cwiki-us-angular-app 这个地址将会自动将 GitHub 中的 https://github.com/cwiki-us-angular/cwiki-us-angular-app 项目导入到编辑器中。 显示的界面如下: 请注意,stackblitz 是通过 URL 来进行项目导入的。 官方的说明连接如下: https://stackblitz.com/docs#import-from-github 简单来说,是使用下面的链接,告诉 stackblitz 到哪里去获取源代码。 stackblitz.com/github/{GH_USERNAME}/{REPO_NAME} 如果你还希望使用分支,那么可以使用下面的链接: .../github/{GH_USERNAME}/{REPO_NAME}/tree/{TAG|BRANCH|COMMIT}  

2019年05月17日 0Comments 653Browse 0Like Read more
Angular

Angular 服务器默认的启动端口是多少

Angular 服务器启动的时候,如果不添加任何参数,那么默认的启动端口是多少? 在默认情况下,Angular 的启动端口是 4200

2019年05月16日 0Comments 570Browse 0Like Read more
Angular

Angular 如何修改启动的端口

在默认的情况下 Angular 启动使用的是端口 4200。 如果修改这个启动的端口,比如说我们希望再  4100 端口上启动? 可以在启动的时候添加端口参数 --port。 例如使用下面的启动命令: ng serve --open --port 4100 就可以让你的 Angular 应用在 4100 端口上启动。  

2019年05月16日 0Comments 476Browse 0Like Read more
12
Categories
  • Algorithm(算法)
  • AMQP
  • Angular
  • CI
  • Compile And CI
  • Computer Science
  • Confluence
  • DataBase
  • Gradle
  • Hibernate
  • IDE
  • Java
  • Jersey
  • Jira
  • MariaDB
  • PrestaShop
  • Spring
  • Spring Batch
  • U.S.
  • U.S. Travel
  • USRealEstate
  • VisaFn

COPYRIGHT © 2020 CWIKIUS. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

湘ICP备2020018253号-1