序言
这次学习笔记,来自国外的一篇教学案例,好东西就得分享。
Angular Input Output Tutorial Example From Scratch
Step 1: Install Angular Project via AngularCLI
Step 2: Create parent and child components.
Step 3: Define HTML for parent component
Step 4: Define HTML for child component
Step 5: Use Input to display parent component value
Step 6: Pass value from child to parent component
代码实现与解析
第一步 创建一个project
ng new input
说明:
(1) 在 AngularJS时代,创建一个NG工程很简单,只是在html文件中,引入 AngularJS即可。 进入 Angular 新时代后,是通过CLI 来创建工程的。 所以需要事先安装Angular 的 CLI。 而且,一旦创建就要默认生成很好很多文件, 自然,这个创建过程需要耐心的等待,花些时间是必须的。
(2)在这个创建工程中,不仅仅是create 了一些文件,而且还自动生成了它的依赖包,也就是说,自动执行力 npm install。 整个工程 380M,一行代码还没写呢!
(3) 一旦创建成功,你肯定会迫不及待地想运行看看效果。 通常,会不加思索地运行它。
ng serve -o
奇怪现象产生了,咦,不是说好了 hello world 会自动生成的吗? 怎么报这个错呢? 吓死宝宝了。 呵呵
image.png当然,聪明的你,会想起百度学习法。在百度上搜索下看看, 搜索:
You seem to not be depending on "@angular/core". This is an error.
神人多了去了,招数也多了去了,有人告诉你,重新安装 Angular CLI; 有人告诉你重新 npm install, 甚至也有告诉你,重新安装 node.js 就差让你换一台电脑了。
其实哪里有这么复杂,报错的意思,并不是说依赖关系出了问题,而是根本没找见 @angular/core 。 经验告诉我们,找不见文件,通常是路径出了问题。
我们刚才创建了的工程路径是 input, 而指令所在的路径根本不是 input 啊! 这时候的你,肯定恍然大悟,原来如此!
进入到该工程所在路径:
cd input
这时,再来运行以下
ng serve -o
奇迹出现了,世界是多么的其妙! 啥也不说了,看图吧:
image.png重要的事情说三遍: 创建工程后,一定要进入到该工程所在的路径!
重要的事情说三遍: 创建工程后,一定要进入到该工程所在的路径!
重要的事情说三遍: 创建工程后,一定要进入到该工程所在的路径!
Step 2: Create parent and child components.
ng g c parent
ng g c parent
说明:
(1)此时,Angular APP 还在运行中,我们要执行新的命令了,如何退出呢?—— Ctrl+C
创建组件: g: generate ; c :component
(2)虽然创建了两个component,因为还没有关联起来,即便运行,其结果也不会有什么变化。
APP 的入口是 app.component.html ,在入口文件中,添加以下代码:
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<app-parent></app-parent>
</div>
说明:
<app-parent></app-parent> 这个位置,是预留给 parent.component.html 的。
Step 3: Define HTML for parent component.
在 parent.component.html 中,添加以下代码:
<h3>Parent Component</h3>
<label>Bitcoin price</label>
<input type="text" />
<p>Value of child component is: </p>
此时,再来运行,看到的首页变化了。 parent.component.html 文件加载了进来,显示如下:
image.png思路: 在parent页面上输入文字, 在child 页面上显示文字。 并且, parent 与 child 在同一个页面上。所以,需要在 parent.component.html 中,引入 <app-child>
首先,在child.component.html 文件中,添加以下代码:
<h3>Child Component</h3>
<label>Child Component</label>
<input type="text" />
<p>Value of parent component is: </p>
接着, 在parent.component.html 文件中,引入<app-child>
。代码如下:
<h3>Parent Component</h3>
<label>Bitcoin price</label>
<input type="text" />
<p>Value of child component is: </p>
<app-child> </app-child>
再来运行下,结果如下:
image.png
组件之间的传值,就要开始了!
Step 5: Use Input to display parent component value
@Input 粉墨登场!
详情参考: @Input的应用
Decorator : 修饰符
A decorator is a function that is invoked with @ prefix and followed by class, method, property.
例如: @Input()
踩“坑”开始,请注意!!
在 parent.component.html 文件中,修改代码如下:
<input type="text" #pcomponent (keyup)="0"/>
<app-child [PData]="pcomponent.value"></app-child>
说明:
想获取 <input> 里面的值,怎么办?
简单方法: 设置 <input> 的 reference (参考), 注意写法:
#pcomponent
再将该值,传给 child 页面。方法是:
<app-child [PData]="pcomponent.value"></app-child>
把 <input> 的值,传给一个变量 PData 。 注意, 加上 [ ], 起到“插补”的作用。
在 child.component.html 文件中,添加代码:
export class ChildComponent implements OnInit {
@Input() PData: string;
constructor() { }
ngOnInit() {
}
}
说明,特别注意:
@Input() PData: string;
@Input() 是一体的,不能分开。
PData 是一个变量,这个变量来自 parent.component.html 的设定
这时候,再来运行,看到如下结果:
image.png如果没有出现你期望的结果,可能出现的“坑”,如下:
“坑”(一):
parent.component.html 中,特别注意这一行代码:
<app-child [PData]="pcomponent.value"></app-child>
[PData]="pcomponent.value" 必须写在 <app-child> 里面,切不可写在标签的之间:
<app-child> [PData]="pcomponent.value" </app-child>
“坑”(二):
[PData]="pcomponent.value" 的赋值必须是一个变量。 简单的直接赋值是不可以的。 不可以这样写:
[PData]="test data"
说明:
Angular 5.X 传值的玄妙之处就在于此。 [ ] 插补(interpolation)的用法。 如果还没理解,先跳过去,记住它的用法就可以了。
Step 6: Pass value from child to parent component.
思路:在child 中创建一个 Event, 通过 @Output 修饰符,供 Parent 调用;
parent 无法获取到child,所以 parent 监听 child 的事件,当事件触发时,把child 的值传给 parent。
在 child.component.html 中,添加代码:
<h3>Child Component</h3>
<label>Child Component</label>
<input type="text" #ccomponent (keyup)="onChange(ccomponent.value)"/>
<p>Value of parent component is: {{ PData }}</p>
在 child.component.ts 中,添加代码:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Input() PData: number;
@Output() childEvent = new EventEmitter();
constructor() { }
onChange(value) {
this.childEvent.emit(value);
}
ngOnInit() {
}
}
代码解读:
(1)在 ts 文件中声明一个 onChange 方法,并在 html 的 <input> 标签中调用 onChange 方法。
(2) 为了让 parent 监听 child的事件,通过 @Output() 来声明。
@Output() childEvent = new EventEmitter();
这时候, parent 就可以监听 childEvent 事件了。要注意,这个事件是可以传参的。 具体传什么参数呢?
this.childEvent.emit(value);
传的是这个value。就看给这个参数输入什么了。
接下来, 在 parent.component.html 文件中,绑定这个事件和参数,如下:
<app-child [PData]="pcomponent.value" (childEvent)="CData=$event"></app-child>
同时,在 parent.component.ts 中,声明一个变量:
// parent.component.ts
public CData: number;
在 parent.component.html 中,显示 child的输入值:
// parent.component.html
<h3>Parent Component</h3>
<label>Parent Component</label>
<input type="text" #pcomponent (keyup)="0"/>
<p>Value of child component is: {{ CData }}</p>
<app-child [PData]="pcomponent.value" (childEvent)="CData=$event"></app-child>
代码解读:
为什么要声明 CData 这个变量呢? 套路是: 先赋值给一个变量,然后,在其他地方,调用这个变量。 很通俗吧!
运行结果:
网友评论