好长时间没有更新文章了,无意中看到知乎上的大牛说自己用angular完成私活项目,一周写了一千多个页面,感到很是震惊,在白天有本职工作的情况下,这效率绝对的堪称惊人。这份执着以及对知识熟练应用的程度都值得老衲佩服。
决定好好的学习下angular,废话不多说,妹子镇楼。
好吧,我承认这已经不是妹子了,是老师!这是老师!各位,买定离手啊,老师股要暴涨!老师天外飞仙!啊,是黑丝,是黑丝!老师发动了黑丝攻击!老师的攻击对我产生了破防效果同时造成了九万点伤害,啊!阿伟死了~!
这个……先这样吧,动漫妹子什么的,学习完再说吧。
我们都知道,angular组件间通讯的问题,可以划分成三大类:
- 父组件给子组件传值
- 子组件给父组件传值
- 非父子组件间通讯
我们从高中物理的教育中学到参照系的选定对于物体状态的研究非常重要,这特么就是一个天才的思考模式。以上三种划分方式老衲没有异议,但是叫法不敢苟同,对于老衲这种脑子比较笨的人来说,不太方便理解记忆。我们稍微改变几个文字,变更一下“参考系”。想是理解起来感觉应该大不同。
改动下的结果就是:
- 父组件传值给子组件
- 父组件获取子组件的值
- 非父子组件间通讯
可能觉得没啥区别,看了具体的代码之后我想这种叫法对于更好的理解概念应该是有一定帮助的吧。限于篇幅只梳理前两种,如果文字过长肯定会让人丧失阅读下去的耐心。
父组件传值给子组件 (@Input)
这种应用场景还是比较常见的,例如我们有一个公共头部组件,在每个组建中我们都需要用到它,但是每次引用的时候,我们希望在它有标题的地方都显示和引用它的父组件有关联的文字信息。这个时候就需要父组件在调用子组件的时候给子组件传递一个“钩子”一样的值。然后在在子组件来接收它。
能传递的不只是变量,父组件还能把自己的方法传递给子组件,再狠一点,父组件还能把自己“打包”整个传给子组件。
- 父组件调用子组件的时候传入数据
/*
home组件中调用子组件
title:要传递的值,
例如:public title = "这里是首页";
*/
<app-header [msg]="title"></app-header>
- 子组件引用input模块
/*
在header组件中的component.ts中引用Input模块
*/
import { Input } form '@angular/core';
- 子组件中使用装饰器@Input接收父组件传过来的数据
/*
@input 后面的msg 就是第一步中[msg],两者是一致的。
之后就是使用this.msg来做后续处理;或是在子组件的html中使用{{msg}}来调用
*/
export class HeaderComponent implements OnInit {
constructor() { }
@Input msg : string;
}
需要注意的地方有几点:
- 传入数据时候,如果是变量直接写变量名,如果是字符串需要在
双引号
之内再用单引号
包裹字符串。 - 可以同时传递多个数据。接着写上去就行了。
- 传入数据如果是函数,只需要写函数名不需要加括号
()
,也就是写函数引用。之后调用方法的时候再加()
令其执行调用。 - 要传递的变量名或函数名与传入数据时
[]
内“传递载体”变量的名称可以一致,也可以不一致。但是使用@Input接受数据的时候的名字 必须和[]
的名字一致。 (两者其实是一个东西) - @Input 这几个字符中的i是大写,是大写,是大写!!!
父组件获取子组件的值
父组件获取子组件的数据,从代码的形式来说如果叫子组件传数据给父组件,会导致脑子再想的时候多绕一道弯,浪费脑细胞啊。
父组件获取子组件的值有两种形式,一种是主动获取,还有一种是被动接受。
父组件主动调用或叫获取子组件的数据 (@ViewChild)
- 调用子组件时给子组件定义一个名称
/*
这次我们调用底部组件
使用 #ComponentName 的形式来给组件命名,这里我们给底部组件命名为 foot
*/
<app-footer #foot></app-header>
- 父组件引用ViewChild模块
/*
在父组件中的component.ts中引用ViewChild模块
*/
import { ViewChild } form '@angular/core';
- 在父组件使用装饰器@ViewChild获取子组件
/*
装饰器@ViewChild('foot')中foot是前面我们给子组件的命名#foot。
后面的footer123是我们父组件调用子组件时的“别名”,
后面我们就可以用this.footer123调用到子组件的数据和方法了。
所有操作都是在父组件中进行的,如果这里叫子组件传值给父组件,估计没理解透的时候看到这个,脑子会卡那么一下。
(加上123为了明显区别,别杠~)
*/
export class FooterComponent implements OnInit {
constructor() { }
@ViewChild('foot') footer123 : string;
}
父组件被动调用或叫获取子组件的数据 (@Output 和EventEmitter)
这个被动获取的方式,也可以称为子组件广播数据给父组件。应用的是不是很多,但是很重要!很重要!很重要!在需要解耦的时候这是最常用的方式。一定要理解。
看到EventEmitter
了解Node的你肯定会笑出声来,我们都知道EventEmitter
的核心就是事件触发与事件监听器功能的封装。这里要用到它,这种方式肯定是通过事件监听来实现的了。
- 在子组件中引入output模块和EventEmitter模块
/*
在子组件的component.ts中引入两个模块
*/
import { Output , EventEmitter} form '@angular/core';
- 在子组件中使用装饰器@Output和EventEmitter来实例化对象
/*
在子组件的component.ts中 使用装饰器@Output和EventEmitter实例化
*/
export class FooterComponent implements OnInit {
@Output() private OuterEventName = new EventEmitter<string>();
constructor() { }
}
- 子组件中通过EventEmitter对象的OuterEventName这个实例来广播数据给父组件
/*
通过sendParent()方法来触发this.OuterEventName.emit('来自子组件的信息')
*/
export class FooterComponent implements OnInit {
@Output() private OuterEventName = new EventEmitter<string>();
constructor() { }
//-----------------新代码--------//
sendParent(){
this.OuterEventName.emit('来自子组件的信息')
}
- 父组件调用子组件的时候,定义接收事件
/*
(OuterEventName)中的OuterEventName就是前面的EventEmitter对象OuterEventName实例,
两者名字要一致。doChild()方法就是子组件广播数据时候父组件中接收数据的方法
*/
<app-product (OuterEventName)="doChild($event)"></app-product>
- 父组件接收事件
/*
参数e就是子组件传递的方法
*/
doChild(e){
//dosomethin
}
这样当子组件中的sendParent()方法执行的时候,会广播数据到父组件,父组件中的doChild()就会被触发执行,从而获取子组件传递来的数据。
后记
要下班了,不写了。有问题留言,我再修改吧!