将英雄们显示在 Mat-Card 上後,我们进一步地要对英雄资料做点加工,并且制作英雄详细介绍页面。今天会完成下列事项:
现在这些狗狗都召唤出来了,今天天气不错,请问现在是要去遛狗吗?
(说话小心一点,吕布在你後面他很火。)
请问,这群狗是要怎麽拯救世界呢?他们是能变狗狗币吗?
(狗狗币你确定不是来乱的吗...看来你被外表所迷惑了啊。今天我们来让你对这些英灵有更深刻的认识吧!)
你是说品种之类的吗,我看他们品种都一样啦...。
在 TypeScript 里,我们可以用介面(interface)来制作资料模型档案。这可以在开发期间提供很大的帮助,比如在资料传递时提供静态检核,或是在使用物件时,能够提示你物件所拥有的属性,大幅地减少拼字错误的可能性——这些,都仰赖我们确实地制作资料模型档案。
我们可以将资料模型档案放置在 shared 目录下:
src
⌞app
⌞ shared
⌞ models
hero.model.ts
现在我们在 hero.model.ts
档案制作规范英雄物件会有的属性或方法:
export interface Hero {
id: number; // id
name: string; // 姓名
image?: string; // 图像
hp: number; // 生命值
attack: number; // 攻击力
defence: number; // 防御力
weapon?: string; // 武器
skill?: string; // 必杀技
}
在介面中,若後方带有 ? 表示这是可选属性,物件中可能有这个属性、也可能没有。例如,英雄可能不会配有武器(weapon),例如叶问。叶问拿武器就好比 macbook 配滑鼠会被笑的(乱讲)。
接着,我们就制作好的介面放置到对应的位置,打开 hero-list.component.ts
,我们在使用 Http 请求英雄资料时,同时宣告会取得的资料型态(在 http.get後方加上 <Hero[]>):
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Hero } from './../shared/models/hero.model';
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {
heroList: Hero[] = [];
constructor(
private http: HttpClient
) {}
ngOnInit(): void {
this.http.get<Hero[]>('api/heros').subscribe((heroList) => {
this.heroList = heroList;
});
}
}
同时,也在宣告属性 heroList 的同时标注他的介面为 Hero[]
。这样当取得资料型态不一致时,在开发阶段就会看到错误讯息。也因为确实地标明了属性的介面,在开发时就可以享受到属性提示的好处:
因为我们的经费没有那麽多,请不起这麽多的英灵(其实是为了演示方便),我们先将英灵总数调降为 3 人,并为他们填上较详尽的资料,请将下列资料更新到 db.json
中:
{
"heros": [
{
"id": 1,
"name": "吕布奉先",
"image": "https://i0.zi.org.tw/ddm/2021/06/1624399697-0ad6a83f8d158a95db281bdd223a56b1.jpg",
"hp": 999,
"attack": 900,
"defence": 900,
"weapon": "方天画戟",
"skill": "天喰",
"description": "出身於三国时代,号称是中华历史中个人战力最强的男人,武器为方天画戟,必杀技为「天喰」。"
},
{
"id": 2,
"name": "亚当",
"image": "https://i0.zi.org.tw/ddm/2021/06/1624400056-7d129b933d846f4350625816bb9d5992.jpg",
"hp": 500,
"attack": 999,
"defence": 100,
"weapon": "指虎",
"skill": "神虚视",
"description": "为全世界人类的爸爸,是神按照自己的模样打造的第一个人类,人类档案编号为00000000001,也是最接近神的男人,拥有必杀技「神虚视」,能复制所有的技能,不过他的眼力是有上限的。"
},
{
"id": 3,
"name": "佐佐木小次郎",
"image": "https://i0.zi.org.tw/ddm/2021/06/1624400405-c2a2d77d29397a6bfef69367fbeba681.jpg",
"hp": 600,
"attack": 700,
"defence": 600,
"weapon": "备前长船长光",
"skill": "双燕斩虎万仞缭乱",
"description": "日本战国时代的剑士,剑派为岩流,被喻为是「史上最强大的失败者」,他屡战屡败,但他会从每次的失败中学习并进步,即使到了地狱依然不断在学习剑术,他拥有能预判敌人动作的「千手无双」技能,做出事先的闪躲,而必杀技为结合日本各大剑术流派的集大成招式「双燕斩虎万仞缭乱」"
}
]
}
资料来源:多多看电影。《终末的女武神》对战名单|13位最强人类+13最强神只 必杀技角色解析总整理!
并调整 hero-list.component.html
显示的资料:
<div class="hero-container">
<mat-card class="hero-item" *ngFor="let hero of heroList">
<mat-card-header>
<div mat-card-avatar></div>
<mat-card-title>{{ hero.name }}</mat-card-title>
</mat-card-header>
<img mat-card-image [src]="hero.image" [alt]="hero.name">
<mat-card-content>
<p>
{{ hero.description }}
</p>
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>
</div>
这里,我们在 中使用了属性系结(property binding),将 <img>
拥有的属性放入英雄资料。目前我们的画面如下:
现在我们要制作一个英雄资讯细节元件,让使用者可以进一步浏览英雄资讯,让我们到 app 资料夹下执行:
ng g c hero-detail // g for generate, c for component
档案目录结构如下:
src
⌞app
⌞ hero-list
⌞ hero-detail
⌞ hero-detail.component.html
⌞ hero-detail.component.css
⌞ hero-detail.component.ts
接着分别编辑下列档案:
hero.detail.component.ts
:
import { Component, Input, OnInit } from '@angular/core';
import { Hero } from '../shared/models/hero.model';
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
@Input() hero: Hero | null = null;
constructor() { }
ngOnInit(): void {
}
}
@Input()
是个装饰器,当一个属性加上此装饰器时,使用 HeroDetailComponent 元件的地方,就可以针对这个属性 hero 使用属性系结来传递资料。等等我们也会在 HeroListComponent 使用 HeroDetailComponent,并对 hero 进行属性系结。
以及hero.detail.component.html
:
<mat-card *ngIf="hero">
<mat-card-header>
<div mat-card-avatar></div>
<mat-card-title>{{ hero.name }}</mat-card-title>
</mat-card-header>
<img mat-card-image [src]="hero.image" [alt]="hero.name">
<mat-card-content>
<mat-list>
<mat-list-item>HP: {{ hero.hp}}</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>Attack: {{ hero.attack }}</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>Defence: {{ hero.defence}}</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>Weapon: {{ hero.weapon}}</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>Skill: {{ hero.skill}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
</mat-card-content>
</mat-card>
并且,因为使用了更多 Angular Material 元件,我们也要在 app.module.ts
汇入 MatDividerModule
及 MatListModule
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatListModule } from '@angular/material/list';
import { AppComponent } from './app.component';
import { HeroListComponent } from './hero-list/hero-list.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
@NgModule({
declarations: [
AppComponent,
HeroListComponent,
HeroDetailComponent
],
imports: [
BrowserModule,
HttpClientModule,
BrowserAnimationsModule,
MatCardModule,
MatButtonModule,
MatDividerModule,
MatListModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
我们已经完成了 HeroDetailComponent ,现在我们将它放到 HeroListComponent 上来使用。请调整 hero-list.component.html
:
<div class="hero-container">
<mat-card class="hero-item" *ngFor="let hero of heroList">
<mat-card-header>
<div mat-card-avatar></div>
<mat-card-title>{{ hero.name }}</mat-card-title>
</mat-card-header>
<img mat-card-image [src]="hero.image" [alt]="hero.name">
<mat-card-content>
<p>
{{ hero.description }}
</p>
</mat-card-content>
<mat-card-actions>
<button mat-button (click)="viewHeroDetail(hero.id)">浏览细节</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>
</div>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
我们在下方使用新元件 <app-hero-detail>
,并属性系结 hero ,传入的资料为 selectedHero。而在第一个按钮,我们绑定 click 事件,当发生 click 事件时就要呼叫 viewHeroDetail 方法,并且要将 hero.id 作为参数传入此方法中。
我们的规划是:viewHeroDetail 这个方法会找到选择英雄资料,将资料赋予 selectedHero。之後 selectedHero 便会透过属性系结(绑定 HeroDetailComponent 的 hero 属性),selectedHero 便会将自己传入 <app-hero-detail>
中。现在,我们来 hero-detail.component.ts
实现这个机制:
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Hero } from './../shared/models/hero.model';
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {
heroList: Hero[] = [];
selectedHero: Hero | null = null;
constructor(
private http: HttpClient
) {}
ngOnInit(): void {
this.http.get<Hero[]>('api/heros').subscribe((heroList) => {
this.heroList = heroList;
});
}
viewHeroDetail(heroId: number): void {
this.selectedHero = this.heroList.find((hero) => hero.id === heroId)!;
}
}
目前的画面如下,如果点击不同英雄卡片中的按钮「浏览细节」,下方的细节资讯就会切换显示。
教材网址 https://coding104.blogspot.com/2021/06/java-p...
The Bridge design pattern decouples an abstraction...
实作前准备 需要先了解以下主题: Method Wrappers: Around Aliases M...
夥伴们大家好,今天要来说明如何安装Django啦~~~ 但是在安装前我们要先查看一下,我们使用的py...
动态元件(Dynamic-Components)是指Vue可以根据传入参数的,来去切换不同的元件。 ...