本文是自己的学习笔记,主要参考资料如下。
- B站《2020最新Angular实战教程》,老陈打码制作,https://www.bilibili.com/video/BV1i741157Fj?p=2。
组件中有一些hook可以供我们操控组件,比如组件初始化时,组件数据发生更改时。这些hook都是组件自带的一些方法,方法名都是由ng
加上一些名词组成,比如初始化时的ngOnInit
,数据更改时ngOnChanges
。
下面详细介绍各个hook的触发时机。
construct函数不算是hook,但是它发生的时间是在所有hook之前,放在这里比较好记忆。
我们在根页面的ts写下面的代码,在constructor函数中写一个打印信息,
然后打开根页面,查看打印信息。因为根页面这个组件被加载,所以运行constructor的代码。
当这个组件有输入时,每次输入进来赋值后就会调用该hook。并且初始化时,会先执行该hook,再执行 ngInit
。当然,如果组件没有输入,那该组件从出生到销毁都不会调用该hook。
所谓的输入就是指组件中的@Input()
标识的变量。
下面是例子。
新建一个组件app-on-change
,在该组件中定义一个输入参数,构造函数,ngChanges
和ngInit
。
@Component({
selector: 'app-on-change',
templateUrl: './on-change.component.html',
styleUrls: ['./on-change.component.css']
})
export class OnChangeComponent implements OnInit {
@Input() number;
constructor() {
console.log('onChang component: constructor');
}
ngOnChanges(): void {
console.log('onChang component: ngOnChanges');
}
ngOnInit(): void {
console.log('onChang component: ngOnInit');
}
}
根组件中引入该组件,将值传入到app-on-change
中,并创建一个button,使button每次点击后都会给app-on-change
传入新的值,不断地触发其ngOnChanges
hook。
html
代码
<app-on-change [number]="number">app-on-change>
<button (click)='onClick()'>buttonbutton>
ts
代码
// app.component.ts
export class AppComponent {
number = 0;
constructor() {
console.log("constructor");
}
ngOnChanges() {
console.log("ngOnChanges");
}
onClick() {
this.number++;
}
}
刚启动时,先执行根页面app-root
的constructor
和其他hook。因为根页面没有输入,所以没有触发根页面的ngOnChange
的hook。
从第二行开始就执行app-on-change
的constructor
和其他hook。
之后我们点击button,修改number
的值,使其不断传入组件app-on-change
中,不断触发其ngOnChanges
的hook。结果如下
组件第一次加载时会调用该hook,要注意的一点是该hook的执行顺序是在ngOnChanges
之后。
示例就不写了,可以参考1.2
中的内容。
之后的hook暂时先不写,很少用到。所有的hook的执行顺序在官网中有写
指令可以理解成普通dom元素的函数,我们可以借助指令自定义dom元素的函数。
比如这里appTestDirective
就是一个自定义的指令,它的作用是将h1
这个元素的class
从原来的2
变为abc
。
<h1 class="'2'" [appTestDirective]="abc">h1h1>
下面就创建一个指令,看看指令的用途。
使用ng g directive name
创建指令,好处不用多说,和ng g component name
一样。
现在创建一个指令ng g directive directive/testDirective
。指令结构和component类似,就是没有css文件。
指令相当于是dom文件的函数,我们需要定义一些参数来接收dom元素和其他一些参数。
在construct函数中使用依赖注入的方式获取dom元素,并且输入这个dom元素。具体代码如下
@Directive({
selector: '[appTestDirective]'
})
export class TestDirectiveDirective {
constructor(public ref: ElementRef) { }
ngOnChanges() {
console.log(this.ref);
}
}
要注意ref的前面要有public,这样依赖注入进来的ref才能在constructor函数以外使用。
这种依赖注入的方式不仅可以在指令中使用,也可以在组件中使用。
这里先写到这里,等会将指令使用到具体的dom元素中再看看ref的内容是什么。
这类参数是用来辅助的。定义方式和在组件中定义普通的输入类似。
@Directive({
selector: '[appTestDirective]'
})
export class TestDirectiveDirective {
@Input() appTestDirective;
constructor(public ref: ElementRef) { }
ngOnChanges() {
console.log(this.ref);
}
}
要注意,这个输入的名字必须和指令的selector一样,但不要其中的中括号。
我们在app.component.html
中使用指令。使用来搭配指令。
<h1 class="'2'" [appTestDirective]="abc">h1h1>
其中,abc是app.component.ts
中定义的一个变量。
export class AppComponent {
abc = 'class';
}
这段话可以理解成appTestDirective
是我们自定义的一个事件,在这个事件对应的逻辑中我们可以获取dom元素和一些额外的参数进行操作。
之后我们在指令中写入一些逻辑来改变h1
元素的类名。
export class TestDirectiveDirective {
@Input() appTestDirective;
constructor(public ref: ElementRef) { }
ngOnChanges() {
console.log(this.ref);
this.ref.nativeElement.className = this.appTestDirective;
}
}
h1
的类名原本是2,但上面代码通过指令将其类名改成了变量abc的值,即class
。