如果我会一些Javascript的基础知识,我可以
快速地上手Angular
吗?或者说,我是一名前端工作者,没有接触过Angular,我该如何
快速地使用Angular进行日常开发
呢?我是轻流前端团队的一员,用了一周的时间从之前没有使用过Angular到了解Angular 可以进行一些简单的开发,在这之中收获良多,希望可以给同样想了解和使用Angular的小伙伴带来一些参考。
1. 组件是什么?
组件(Component),就是可以实现我们需求的一个小块。一个自定义的按钮、一个表单、一个页面等等,都是组件。组件是Angular项目的核心概念,我们页面的一切都是由一个一个的组件搭建起来的。组件化的目的有两个:一是解耦,把逻辑封装在内部,每一个组件都是功能相对单一和独立的个体;二是复用,封装成组件之后不仅可以在项目内部复用,甚至可以沉淀下来跨项目复用。
// 以一个简单的button为例
@Import { Component } from ‘@angular/core’;
@Component({
selector: 'demo-button',
template: `<button class="demo-btn">{{btnText}}</button>`,
styles: [
`.demo-btn {
color: red;
}`
]
})
export class DemoButtonComponent {
btnText: 'click me';
}
上面就是一个很简单的组件,一个文字为红色的’click me’的按钮,在页面中使用也很简单:
<body>
<demo-button></demo-button>
</body>
上面的代码中,我们注意到,从@angular/core中导入了 Component,并且使用@Component() 这个修饰器说明了我们的 DemoButtonComponent 是一个组件。@Component() 中我们传入了几个配置项 selector、template、styles,我们分别讲一下它们是什么意思:
selector:顾名思义,它是一个选择器(与css选择器用法一样),选择什么呢?选择什么样的标签会触发我们DemoButtonComponent这个类的构造。
template:即我们这个组件的模板,除了使用template这个属性,我们还可以使用templateUrl这个可选属性,可以导入一个html文件作为模板。
styles:组件内部样式。这是一个数组,除了项demo中使用,也可以导入样式文件。
@Component({
selector: 'demo-button',
templateUrl: './demo-button.html'
styles: [
`demo-btn: { color: red }`,
'./demo-button.scss'
]
})
那么,我们如何在组件中做更多的事情呢?我们再看Angular的生命周期钩子。
2. Angular生命周期钩子
Angular生命周期钩子angular.cn
Angular组件的生命周期中,暴露八个回调函数在不同的阶段给开发者使用(类似于window对象的onload、ready),分别为:
在代码中使用钩子:
@Import { Component,OnInit, OnDestroy } from ‘@angular/core’;
@Component({
selector: 'demo-button',
template: `<button class="demo-btn">{{btnText}}</button>`,
styles: [
`.demo-btn {
color: red;
}`
]
})
export class DemoButtonComponent implements OnInit, OnDestroy {
btnText: string;
ngOnInit(): void {
this.btnText = 'click me';
}
ngOnDestroy(): void {
//do something
}
}
这样,我们就可以通过Angular暴露给我们的这些生命周期钩子,在组件生命周期的不同阶段去做不同的事情,比如组件的初始化、事件监听的销毁等等。
3. 组件通信
因为Angular项目中,页面是由一个一个的组件搭建而成,整个架构是纵向分层的。我们可以把一个页面想像成一个组件树,小组件构成更大一些、功能更丰富的组件,大一些的组件构成了页面的一些功能块,最终的页面是由组件一级一级地构建而成。所以,数据的传输、组件之间的通信是我们必须要解决的一个问题,那么这个问题Angular是如何解决的呢?Angular给我们提供了两种方式。
3.1 Input和Output(输入输出)
我们先来写两个简单的父子组件:
@Import { Component, EventEmitter, Input, Output } from ‘@angular/core’;
@Component({
selector: 'demo-input',
template: `
<input [(ngModel)]="value" type="{{inputType}}"><button (click)="ok()">ok<button>
`
})
export class DemoInputComponent {
@Input() inputType: string;
@Output() onOk: EventEmitter<string> = new EventEmitter();
value: string;
ok(): void {
this.onOk.emit(this.value);
}
}
@Import { Component } from ‘@angular/core’;
@Component({
selector: 'demo-form',
template: `
userName: <demo-input [inputType]="'text'" (onOk)="name = $event"></demo-input>
passWord: <demo-input [inputType]="'password'" (onOk)="pwd = $event"></demo-input>
`
})
export class DemoFormComponent {
name: string;
pwd: string;
}
在这两个组件中,我们在父组件的模板中 使用 ‘[inputType]’ 向子组件中输入了inputType属性,并在子组件中使用 ‘@Input()’ 接受了这个输入的属性。在子组件中,点击按钮时,使用’@Output()’事件发射器向外发射了’onOk’事件,然后在父组件中使用 ‘(onOk)’ 接受到了这个发射出来的事件。
我们可以使用input和output在父子组件中方便快捷地进行通信。
3.2 Service
父子组件可以使用Input和Output方便地通信,非父子节点呢?如果使用Input和Output层层传递进行通信的化,代码会非常的难看,有没有什么别的方法可以更方便地进行组件通信呢?
当然有,那就是我们的service(服务)。同样看一个例子:
@Import { Component, OnInit } from ‘@angular/core’;
@Component({
selector: 'demo-input',
template: `
<input [(ngModel)]="value" type="{{inputType}}"><button (click)="ok()">ok<button>
`
})
export class DemoInputComponent implements OnInit {
inputType: string;
value: string;
constructor(public formSrv: FormService ) {}
ok(): void {
this.formSrv.onOk.emit(this.value);
}
ngOnInit(): void {
this.inputType = this.formSrv.inputType;
}
}
@Import { Component, OnInit } from ‘@angular/core’;
@Import { FormService } from './form.service.ts';
@Component({
selector: 'demo-form',
template: `
userName: <demo-input></demo-input>
`
})
export class DemoFormComponent implements OnInit {
name: string;
constructor(public formSrv: FormService ) {
this.formSrv.onOk.subscribe(res => {
this.name = res;
});
}
ngOnInit(): void {
this.formSrv.inputType = 'text';
}
}
import { EventEmitter, Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class FormService {
inputType: string;
onOk: EventEmitter<string> = new EventEmitter();
}
在这个service中,我们把它的’providedIn’设置为‘root’,表示这个类在整个项目中是单例的,所以我们可以用它来存放一些组件公用的数据或者状态。当然这个的写法并不标准,在Angular中的Module和Compnent中都可以配置provider,即相对于每一个module或者component都会生成一个service实例。
结尾
作为三大前端框架之一,Angular的强大毋庸置疑,我们都是学习者和探索者(甚至是创造者),还有很多东西我现在也没有搞清楚,不过只要我们有心并且能付诸行动,必定天堑变通途。