昨天我们的 Component 只有简简单单的一行 “ironman works!” 其他啥都没有。今天,我们就来替他加点东西,让它显示资料。首先我们先在 ironman.component.html 用原生 HTML 刻出丑丑的使用者资讯页面,存档後我们丑丑的使用者资讯就会长在主页的中间
如果已经执行 ng serve -o 指令,而且没有 ctrl + c 或关闭命令提示字元,存档之後 Angular 会自动套用变更并刷新页面
这时候因为一切从简,连使用者资讯都是写死的字串,但是我们当然不能这麽做,我们一定得把它的资料来源跟某个地方做连结,这样哪天资料做了变更,我们的页面才能正确地更新。
首先,我们来介绍最简单的资料系结方法 – 内嵌系结就是简单直接的把 component.ts 里的变数直接拿来嵌入 HTML 中,语法的规定是:在 HTML 用 "双大括号" 把变数包起来。让我们从刚刚的 HTML 把数值搬进 ts 档,用变数存起来,然後在 HTML 中加入内嵌系结的语法
// ironman.component.ts
export class IronmanComponent implements OnInit {
constructor() { }
userId = 1;
userName = 'Alice';
email = '[email protected]';
verified = 1;
ngOnInit(): void {
}
}
<-- !ironman.component.html -->
...
...
<tr>
<td colspan="2">User Name</td>
<td>
<input type="text" value={{userName}}>
</td>
</tr>
...
...
简单的一些改动,就让我们的 HTML 不再是写死的字串。但是,这样还是完全不行啊!你只不过是换个地方写死而已嘛!欸都…是的,目前还是,所以我们接下来要介绍另外一个系结。
好的,接下来,我们要继续改我们的 ironman 元件,让这个元件里不再存写死的资料,而是让别人把资料传给我们的 ironman,然後我们的 ironman 再把资料镶嵌到 HTML 上。
首先,我们先来定义一个使用者资料的介面(interface),这里特别注意一下,Angular 里的介面与 .NET 的介面有些不同,在 Angular 里如果我们只要定义资料的 model 而没有要实作处理逻辑,那我们会用 interface 而不是 class,选用 interface 的原因是,这些用 interface 定义的资料 model 在编译成 js 後会比较省资源。
export interface IronmanUser
{
userId: number;
userName: string;
email: string;
verified: number;
}
上面的宣告中,冒号(:)前面是物件的属性名称,後面是型别。
接着,把刚刚宣告的几个拆散的变数删掉,改成一个 IronmanUser 型别的变数然後给一些预设值,并用 @Input() 装饰器修饰这个变数,@Input() 会告诉 Angular 这个变数预期要接受从外部传进来的值。
@Input()
userInfo: IronmanUser = {
userId: 0,
userName: '',
email: '',
verified: 0
};
改完之後 HTML 的内嵌系结语法会出错,因为我们把资料搬进一个物件里了,稍作修改把这些 error 修掉
...
...
<tr>
<td colspan="2">User Name</td>
<td>
<input type="text" value={{userInfo.userName}}>
</td>
</tr>
...
...
这时候如果直接执行程序,我们的使用者资讯表格的值会是刚刚宣告的预设值,因为我们还没传值给它。现在,让我们从 app.component.ts 传值给 ironman.component.ts,到 app.component.ts 里,加入一个 IronmanUser 型别的变数,然後给有效的值
export class AppComponent {
userInfoFromAppComponent: IronmanUser = {
userId: 1,
userName: 'Alice',
email: '[email protected]',
verified: 1
}
title = 'ironman-frontend';
}
再来,我们就要实际用属性系结把值传给 ironman.component.ts。被 @Input() 装饰器修饰的变数,对外部的使用者来讲,就好像是这个 Component 的属性,我们透过对这个属性赋值,就能把值传递给这个 Component。
到 app.component.html,用中括号选择 ironman.component.ts 所拥有的 @Input() 属性,然後把要传递的物件赋予这个属性。
<app-ironman [userInfo]=userInfoFromAppComponent></app-ironman>
重新执行程序,就会看到我们的资料正确的显示出来了~
什麽?你说我只不过是再换一个地方写死而已啊!欸都…目前好像的确是这样没错…,但是但是!请听我解释!以後我们只要把初始化这个变数的地方改成读档或抓 DB,就不会是写死的了!我们过几天也会讲到 Angular 的 HttpClient,到时候就会从我们之前写的 API 抓资料了。
刚刚所讲的属性系结是从外部元件(AppComponent)送资料给内部元件(IronmanComponent),而我们很多时候也会需要从内部把资料往外送,这个时候,我们就需要用到事件系结。事件系结的运作方式为:内部元件在某个条件下触发一个事件,事件发射器(EventEmitter)把这个这件跟资料一起往外送,当外部元件收到这个事件时,就能针对这个事件作处理。
要使用事件系结,首先我们要到内层(IronmanComponent)的 ts 档新增一个 @Output() 变数,这个变数固定会是泛型的 EventEmitter,後面的角括号里放我们的事件资料的型别。在 import EventEmitter 到档案中的时候,注意要选「从 "@angular/core"」。
@Output()
testOuputEvent = new EventEmitter<IronmanUser>();
有了这个事件发射器之後,我们就能在程序里自由的决定什麽时候要发送事件,这里,且让笔者偷懒,直接用 setTimeout() 发一个测试事件并携带一笔使用者资料
ngOnInit(): void {
const mockInfo = {
userId: 999,
userName: 'testUser',
email: '[email protected]',
verified: 0
}
setTimeout(() => {
this.testOuputEvent.emit(mockInfo)
}, 1000);
}
而要接收事件的 AppComponent 则是在 HTML 中,用小括号指定接收刚刚宣告的 @Output 事件发射器变数所发的事件,并指定一个 function 来处理这个事件发生之後要做的事。
<!-- app.component.html -->
<app-ironman
[userInfo]=userInfoFromAppComponent
(testOuputEvent)=handleTestEvent($event)>
</app-ironman>
// app.component.ts
handleTestEvent(userInfo: IronmanUser): void {
alert(`AppComponent 接收到 IronmanComponent 丢出的 userInfo: ${JSON.stringify(userInfo)}`)
}
上面的 $event 是固定用法,事件所携带的资料都会存在这个 $event 变数里。在目前的范例中,mockInfo 就会存在 $event 里,handleTestEvent() 的 userInfo 参数就会变成 IronmanComponent 丢出的 mockInfo。
Day25 说要介绍三种 Binding 其实是有点错误的说法,因为有第四种:Two Way Binding(双向系结),如果属性系结是撒尿虾,事件系结是牛丸,那麽双向系结就是
现在,就让我们来做撒尿牛丸,到 ironman.component.ts,再宣告一个 @Output 变数,但是因为要做混在一起做撒尿牛丸,所以这个变数的名称一定是要 "@Input() 变数" 的变数名称 + Change,前面我们宣告 @Input() 变数叫做 userInfo,这个新的 @Output() 变数就必须叫 userInfoChange。
@Output()
userInfoChange = new EventEmitter<IronmanUser>();
接着,再让笔者偷懒一下,一样用 setTimeout() 发射事件
const modifiedInfo = {
userId: 2,
userName: 'Bob',
email: '[email protected]',
verified: 1
}
setTimeout(() => {
this.userInfoChange.emit(modifiedInfo)
}, 1500);
最後,把 app.component.html 原本用中括号的属性系结改成中括号 + 小括号的双向系结,把 userInfo 包起来。
<app-ironman
[(userInfo)]=userInfoFromAppComponent
(testOuputEvent)=handleTestEvent($event)>
</app-ironman>
执行程序,就能看到我们画面上的使用者资料在事件触发之後,一起变成了内部元件发送出来的资料。也就是,双向系结的资料是纠缠在一起的,改变其中一端,另一端会同时被改变。
<<: [铁人赛 Day11] React 原始码的初见面 ——官方 codebase 指南
WordPress 文章的永久连结有分几种模式,预设是「?p=123」这种方式 实际上的连结就变成这...
第一次参加铁人赛,原本以为超前部署,开赛前两个星期就开始准备文章存档 本以为一定妥当的啦,没想到後面...
废话不多说,我们直接看文件~XD 文件 文件原文:Cache and TLB Flushing Un...
【前言】 嗨嗨大家好,今天的主题延续昨天的检测是否已经安装插件後,紧接着而来的是 MetaMask...
在做新产品开发时,对於用户需求收集,寻找产品切入点,我们常有一个典型的错误假设,那就是认为用户最知...