我们往往把 `C层的数据自动向V层传输的机制`叫做`数据绑定`,把`V层数据自动C层传输的机制`也叫`数据绑定`。本节中讨论`C -> V`的绑定机制。在Angular中C层向V层的数据绑定是隐性的:C层中声明的属性均被自动绑定到V层。 >[info] C层:app.component.ts;V层:app.component.html。 # 数据绑定 app.component.ts ~~~ export class AppComponent { constructor(private httpClient: HttpClient) { // 向8080端口的helloWorld路径发起请求 httpClient.get('http://localhost:8080/helloWorld') .subscribe(success, error); } title = 'hello-world'; ➊ } ~~~ ➊ C层定义了title属性,则在V层中可以直接显示该属性的值。 # 数据显示 app.component.html ```html <h1 style="text-align: center; margin-top: 100px;"> {{title}}!➊ </h1> <router-outlet></router-outlet> ``` ➊ V层中显示绑定的数据title。 ## 测试 ![](https://img.kancloud.cn/f5/25/f5256e1c81571a3f6cdf2f7d0dca310c_488x238.png) # 在V层显示后台返回数据 想将后台返回的数据绑定给V层,只需要改变C层中的`title`变量赋值就可以了。`title`的值改变会将会自动的更新显示页面中。 ## 匿名函数 在处理后台返回数据以前, 对原代码进行稍许整理使其更符合通用的JS编程风格。 在JS中,我们可以在使用某个函数时,直接将函数定义在参考中,就好比: app.component.ts ~~~ export class AppComponent { constructor(private httpClient: HttpClient) { // 向8080端口的helloWorld路径发起请求 httpClient.get('http://localhost:8080/helloWorld') .subscribe( success, ➊ error); } title = 'hello-world'; } /** * 在控制台打印传入值 * @param data 任意数据 */ function success(data) { ➋ console.log('请求成功'); console.log(data); } ~~~ 等价于 ~~~ export class AppComponent { constructor(private httpClient: HttpClient) { // 向8080端口的helloWorld路径发起请求 httpClient.get('http://localhost:8080/helloWorld') .subscribe( function success(data) { ➌ console.log('请求成功'); console.log(data); }, error); } title = 'hello-world'; } ~~~ ➊等于➋,所以使用➋替换➊后,就变成了➌。 以上代码还等价于 ~~~ export class AppComponent { constructor(private httpClient: HttpClient) { // 向8080端口的helloWorld路径发起请求 httpClient.get('http://localhost:8080/helloWorld') .subscribe((data) => { ➍ console.log('请求成功'); console.log(data); }, error); } title = 'hello-world'; } ~~~ 由于➌只会被用到1次,所以我们可以省略它的名字,便简化为了➍。在后续的教程中,我们会越来越多的使用这种方式。 ## 我的点滴 时间回到20年前自己还刚刚上高中的时候,有一天了解到原来住校生有晚自习。带着好奇的心情上了一晚上了,教室里无数展日光灯把环境照亮,那种感觉别提有多舒服了,突然感觉到晚上能有这么明亮的教室学习是一件非常幸福的事情。从那时候起,开始了走读生的晚自习生活。晚自习会上到9点钟,然后和同学骑自行车走到3公里的国道回家,那时候车比较少,到晚上的时候一般就是拉稻草的车或一些拉货的四轮车,少许会有几辆摩托车。 有一天自习完如常的和几个同学(只记得王乐超一个了)一起回家,半路上突然发现路边摔着一辆摩托车,预感到可能有事情发生后我们下车在摩托周围开始找人,果然不远处还躺着一个人。说实话那时候吓坏了,人碰到这种事情老往最坏的地方想,我们尝试着用手轻推了几下并喊了几下,最后发现人还活着于是问了电话号码,然后分工合作:有同学守着他,而我和另外的同学则去村里找有电话号码的人家赶快去给他家人打电话求助。只听接到电话的那头两口子已经开始不淡定了,过了半小时左右他家人到了,发现原来是自己的邻居家的小孩。。而恰好的是,这个有电话的人家前些天刚刚给自己的儿子买的摩托车。 把那人送上车后,我们几个心里踏实的各回各家了。当初的那个人并不知道我们的名字,我们亦然。可能在后面的人生路上,我们还有过几面之缘,也可能至此再也没有见过,或者他后来一直就在我身边。但这些都不重要,重要的事我们在帮助了他的时候,并不需要知道他的名字。 ***** 在编程的世界里把这种情景的处理叫做**匿名函数**。 ***** 在现实生活中,匿名函数太普遍了。比如今天我们坐地铁来上班,我们并不知道地铁司机的姓名,但这个妨碍他来驾驶地铁这个事实;出了地换,你买早点时我没有问题老板叫什么名字。或者正在学习教程的你,可能正处于河北工业大学的教室里,此时你可能都不知道授课教师的姓名。我们的生活中,有太多太多的才肩而过,一面之缘了。 > 我不知道你来自哪里,不知道你的过去,甚至于连你的姓名我都不知道,但这些都不重要,因为你活生生的就在这里! ---- 致`匿名函数` # 赋值 app.component.ts ~~~ constructor(private httpClient: HttpClient) { const self = this; ➊ /* 向8080端口的helloWorld路径发起请求 */ this.httpClient.get('http://localhost:8080/helloWorld') .subscribe( function success(data: { message: string }) { ➋ self➌.title = data.message; console.log(data); }, error); } ~~~ * ➊ 常规写法,此处的this表示为:本对象。所以此行代码解释为:self = 本App组件对象。 * ➋ 声明`data`参数接收的类型。作用有两个:其一为调用`自己`(指这个匿名方法)的方法规定了数据类型,指调用此方法向参考`data`传值时,该值中必须有`message`字段且该字段的类型必须为`string`。其二是为`自己`在方法体内部使用`data`对象时提供类型参考。 * ➌ 设置**App组件对象**的title值为data.message ## 测试 ![](https://img.kancloud.cn/0d/ff/0dff3eb3baa0c3fe5b42e84be562bf5a_490x405.png) # 主要数据流如下 ![](https://img.kancloud.cn/b0/a2/b0a28781019c343826bbb992ee512d32_800x600.gif) # 本节小测 尝试抛弃`self`而直接使用`this`,请测试看会发生什么,那么为什么会这样呢? app.component.ts ~~~ constructor(private httpClient: HttpClient) { const self = this; /* 向8080端口的helloWorld路径发起请求 */ this.httpClient.get('http://localhost:8080/helloWorld') .subscribe( function success(data: { message: string }) { this.title = data.message; ➊ console.log(data); }, error); } ~~~ ➊ 在这里直接使用this ## 上节答案 实现的方案有很多种,在此给出其中的两种: 方案一: ~~~ class Yunzhi { private input: string; public get(input: string) { this.input = input; return this; ➊ } public subscribe(successFunction, errorFunction) { if (this.input === 'a') { successFunction('hello success'); } else { errorFunction('hello error'); } } } ~~~ ➊ 在get方法中,将`this 自己`做为了返回值。自己中存在➋subscribe方法。 ➋ 接收两个参数,作者心里认为这两个参数的类型是函数类型,所以在内部代码执行了 `successFunction()`,`errorFunction()`。 方案二: ~~~ class Yunzhi { public get(input: string) { return new Observable(input); ➊ } } class Observable { ➋ private readonly input: string; constructor(input: string) { this.input = input; } public subscribe(successFunction, errorFunction) { ➌ if (this.input === 'a') { successFunction('hello success'); } else { errorFunction('hello error'); } } }, ~~~ ➊ 在get方法中,返回了实例化`Observable`的对象➋,该对象➋存在➌subscribe方法。 > 注意: 不是返回了`Observable`,而是返回了根据`Observable`实例化的对象。`Observable`是个图纸、是个协议、是个功能需求描述,它是看不见摸不着的(抽象的)。根据此楼房图纸盖的楼房是对象,是看的见摸的着的;根据USB协议生产的USB鼠标是对象,是看的见摸的着的;根据用车需求提供的汽车是个对象,也是看的见也摸的着。