25.Angular的使用

1. Angular

Angular、React、Vue并称前端三大框架。

Vue 数据变动 —>页面变动 : 数据劫持+发布订阅模式

React 数据变动 –>页面变动 : setDate() 触发forceUpate

Angular 数据变动 –>页面变动 : 脏检查

2. Angular脚手架的使用

1
2
3
4
5
1.确保本地环境   node\python
2. npm install -g @angular/cli
3. ng new 项目名字
最好项目名字+项目路径不要有中文
4. ng serve --port 4201 //进入项目,启动项目

BP

3. 组件的创建

1
2
3
4
ng generate component foo
ng generate component /home/login

在app.component.html中使用上面创建的组件

4. 插值表达式

1
2
3
4
5
6
7
8
9
10
11
12
<p>login works!</p>
<p>login {{message}}</p>
<p [innerHTML]="message"></p>
<p [innerHTML]="'message'"></p>

<img src="{{ heroImageUrl }}" alt="">
<img [src]="heroImageUrl" alt="">
<img bind-src="heroImageUrl">

<button [disabled]="isButtonDisabled">Button</button>

<p>{{name.split('').reverse().join("-")}}</p>

5. 常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!--1.通过ngFor来遍历数组,可以通过let i=index来获取数组中的序号-->
<p>Heroes:</p>
<ul>
<li [id]="'list-' + hero" *ngFor="let hero of heroes;let i=index">
{{i}}----> {{hero}}
</li>
</ul>

<!--2.通过ngIf来做条件判断-->
<div *ngIf="heroes.length>3; else templateName">有很多英雄</div>
<ng-template #templateName>没有很多英雄</ng-template>

<!--3.通过isSpecial变量来控制div是否有hidden样式:添加class来实现的-->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>

<!--4.通过isSpecial变量来控制div的style的display样式:添加行内样式来实现的-->
<div [style.display]="isSpecial?'block':'none'">Show with class</div>
<div [style.display]="isSpecial?'none':'block'">Hide with class</div>

<!--5.通过ngSwitch来控制多个条件下显示的内容-->
<div [ngSwitch]="currentHero">
<div *ngSwitchCase="'Windstorm'">Windstorm</div>
<div *ngSwitchCase="'Bombasto'">Bombasto</div>
<div *ngSwitchCase="'Magneta'">Magneta</div>
<div *ngSwitchDefault>Tornado</div>
</div>

6. 自定义指令

当angular给我们提供的指令不够用的时候,不能满足我们需求的时候就需要自定义指令了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ng generate directive highlight

import { Directive, ElementRef } from '@angular/core';

@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
//el: 绑定指令的那个页面元素
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}

}

使用自定义指令:
<p appHighlight>Highlight me!</p>

7 事件处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!---
1.绑定属性 <img src="img"></img> <p bind-src="img"></p>
2.绑定事件 <p (click)="save()"></p> <p on-click="save()"></p>
3.js表达式 <p>{{ msg }}</p>
4.*ngFor
*ngIf
<p [ngSwitch]="">
<li *ngSwitchCase="xx"></li>
</p>
-->
foo页面中的{{message}}
<button (click)="onSave()">Save</button>
<button (click)="onSave2($event)">On Save</button>
<button (click)="onSave3($event,'heloworld')">On Save</button>
<button (click)="message = '哈哈哈'">内联事件处理</button>
<button on-click="onSave()">On Save</button>

8. 双向绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
1.	需要在app.module.ts文件中引入FormsModule
//引入双向绑定的模块
import { FormsModule } from '@angular/forms';

//声明App依赖的模块
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],

2. 在需要双向绑定的表单元素中使用[(ngModel)]指令
<input type="text" [(ngModel)]="message">

9.class和style的绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--1.样式的绑定-->
<p class="big bold red">p文字</p>
<!--[class]需要绑定一个变量或者字符串-->
<p [class]="'big'">p文字2</p>
<p [class]="['big','bold']">p文字3</p>
<div [class.big]="true">The class binding is special</div>

<p [ngClass]="{'red':true,'bold':true}">p文字4</p>
<!--2.style绑定-->
<button [style.background-color]="true ? 'cyan': 'grey'" >Save</button>
<button [style.backgroundColor]="true ? 'cyan': 'grey'" >Save</button>
<button [style.font-size.em]="true ? 3 : 1" >Big</button>
<button [style.font-size.%]="true ? 150 : 50" >Small</button>
<div [ngStyle]="{'color':'red',backgroundColor:'yellow'}">这是div</div>

10. 过滤器的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Angular内置的一些过滤器

<!--过滤器-->
<!--1.处理时间的过滤器-->
<h1>{{currentTime | date:'yyyy-MM-dd HH:mm:ss'}}</h1>

<!--2.处理货币符号的过滤器-->
<h1>{{123 | currency }}</h1>
<h1>{{123 | currency:'¥' }}</h1>

<!--3.把对象转换为json字符串-->
<h1>{{{name:'jack'} | json}}</h1>

<!--4.将小数四舍五入,默认保留3位小数-->
<h1>{{'123.134545'| number}}</h1>

<!--5.转换为大小写的过滤器-->
<h1>{{ 'Hello' | uppercase }} </h1>
<h1>{{'Hello' | lowercase}} </h1>

11. 自定义过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.	使用如下命令生成一个过滤器
ng generate pipe msgformat

2. 重写msgformat.pipe.ts文件
export class MsgformatPipe implements PipeTransform {
//value就是要过滤的内容
transform(value: string, ...args: unknown[]): unknown {
return value.split("").reverse().join("");
}
}


3. 在指定页面中使用自定义的过滤器
<!--使用自定义过滤器-->
<h1>{{'zhangsan' | msgformat}}</h1>
1
2


1
2


1
2


12. 路由的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1.	在app.module.ts文件中引入路由模块
//引入路由模块
import { RouterModule, Routes } from '@angular/router';

2. 在app.module.ts文件中写路由配置
//声明路由
const appRoutes: Routes = [
{ path: 'foo', component: FooComponent },
//路由路径、组件和路由数据
{ path: 'login/:id', component: LoginComponent ,data: { title: 'login信息' }},
];

3. 把路由配置信息放到imports中
//声明App依赖的模块
imports: [
RouterModule.forRoot(
appRoutes
),
BrowserModule,
AppRoutingModule,
FormsModule
],

4. 在app.component.html中切换路由

<a routerLink="/foo" routerLinkActive="active">来到foo</a>
<a routerLink="/login/5" [queryParams]="{name: 'zhangsan'}" routerLinkActive="active">来到login</a>

<!-- router-outlet类似于vue中的router-view :作用是用来呈现匹配到的路由的组件信息 -->
<router-outlet></router-outlet>

13. http服务的使用步骤

服务就是针对某个单一或系统功能的封装,Angular中典型的服务有http服务和日志服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
1.	在app.module.ts文件中引入HttpClientModule,并且加入到imports里面
//HttpClientModule
import {HttpClientModule} from '@angular/common/http';

//声明App依赖的模块
imports: [
RouterModule.forRoot(
appRoutes
),
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],

2. 在需要使用http服务的组件中引入HttpClient,并且通过依赖注入把HttpClient对象注入到组件实例中
import { HttpClient } from '@angular/common/http';

//在构造函数中依赖注入当前激活的路由的信息
constructor(
private http: HttpClient
) { }

3. 在组件的ngOnInit方法里面发送请求
ngOnInit(): void {
// 发送get请求
this.http.get('/api/homead').subscribe(data => {
console.log(data)
},
//请求错误
err => {
console.log('Something went wrong!');
});
}

4. 当协议、域名、端口有任何一个不一致的时候会构成跨域请求,此时需要设置代理
4.1 在项目根目录下创建proxy.conf.json文件
{
"/api": {
"target": "http://localhost:3001/",
"changeOrigin": true,
"logLevel": "debug"
}
}
4.2 修改package.json中scripts中的 start配置
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
4.3 重启项目

14. TS变量的声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let nickname: string = '张三';
let isDone: boolean = false;
let age: number = 37;
//模板字符串
let sentence: string = `Hello, my nickname is ${ nickname }.
I'll be ${ age + 1 } years old next month.`



{
//声明一个list变量,他是number类型的数组
let list: number[] = [1, 2, 3];
}
{
//第二种方式是使用数组泛型,Array<元素类型>:
let list: Array<number> = [1, 2, 3];
let list2: Array<string> = ['1', '2', '3'];
}

15. TS元组类型

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

1
2
let x: [ number,string];
x = [1, 'abc'];

16. Any类型

1
2
3
4
//any类型
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;

17. Void类型

1
2
3
4
5
6
7
8
//void类型 : 没有返回值,此时会返回undefined
//function 函数名(函数参数): 函数返回值{ }
function warnUser(): void {
alert("This is my warning message");
}
//当我们声明一个变量是void类型的时候,他的值只能是undefined
let unusable: void;
unusable = undefined;

18. 展开运算符和解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2

//通过解构赋值交换两个变量
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b)

//函数参数解构:
function ff([first, second]: [number, number]) {
console.log(first)
console.log(second)
}
ff([1, 2])

//结构剩余参数
{
let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]
}

//对象的解构赋值
{
let o = {
a: "foo",
b: 12,
c: "bar"
};
//let { a, b, c } = o;
let { a, ...passthrough } = o;
console.log(a, passthrough)
//解构赋值的时候给变量取别名
let { a:a1 } = o;
}

//展开运算符
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [...arr1, ...arr2];

let obj1 = { a: 1, b: 2 };
let obj2 = { c: 3 }
let obj3 = { ...obj1, ...obj2 };
console.log(arr3,obj3)

19. 函数类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//1.函数声明:function 函数名字(参数1,参数2,参数3):函数返回值{函数体}
{
function add(x: number, y: number): number {
return x + y
}
console.log(add(1, 23))
}
//2.函数可选参数
{
function add(x: number, y?: number): number {
return x + 10
}
console.log(add(1))
}

//3.函数默认参数
{

function add(x: number, y: number = 20): number {
return x + y
}
console.log(add(10))
}

//4.剩余参数:一般情况下是所有参数的最后一个
{
function sum(a: number, ...args: number[]): number {
let ret: number = 0
args.forEach((item: number): void => {
ret += item
})
return ret
}

console.log(sum(1, 2, 3))
}

//5.箭头函数
{
//let 变量 = (参数1,参数2):返回值 => { return xx ;}
let add = (x: number, y: number): number => x + y
}

20.类和继承和成员变量修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//基本示例
class Person {
//成员变量如果不写修饰符,默认就是public,此时可以在任何地方访问
public name: string;
age: number;
//加private修饰的变量是私有变量,只能在当前类内部使用
private money: number = 1000000;
//加protected修饰的变量可以在本类以及本类的子类中访问
protected house: string = "希尔顿酒店";


//构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}

sayHello() {
console.log(this.name);
}
}

let zs: Person = new Person('张三', 18);
console.log(zs);

//定义一个学生类继承Person类
class Student extends Person {
num: number;
constructor(num: number,name:string,age:number) {
//当有继承关系的时候,一定要先调用super初始化父类的信息
super(name,age);
//再初始化子类的信息
this.num = num;
}
printMsg() {
console.log(this.house)
}
}
var s: Student = new Student(100, "张三", 18);
s.sayHello()
s.printMsg();
console.log(s.name)

//子类继承父类之后就自动拥有父类非私有的成员信息

21. set和get方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

class Person {
//声明一个成员变量,他的名字是_name
private _name: string;

constructor(name: string) {
this._name = name;
}

//通过set和get方法间接来访问_name
set name(value: string) {
this._name = value;
}
get name() {
return this._name;
}
}

let p: Person = new Person("张三");
//注意:这里面不是直接去访问name成员变量,而是去访问get name(){}方法来间接访问成员变量_name
console.log(p.name);
//注意:这里面不是直接给name成员变量赋值,而是去访问set name(value:string){...}方法间接给_name成员变量赋值
p.name = "哈哈";
console.log(p.name)
//搞清楚:_name才是真正的成员变量,p.name和p.name="xx"是调用对应的set和get方法

22. 静态变量和静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class Person {
//成员变量 拥有者是对象,所以我们需要new Person()之后才能访问name信息
name = "zhangsan";
//加static修饰叫静态变量 拥有者是类,不是对象
static country = "中国";
//加static修饰的方法叫静态方法 拥有者是类,不是对象
static sayhello() {
console.log("hello")
}
constructor () { }
}

let p1 = new Person();
let p2 = new Person();

console.log(Person.country) //静态变量,直接通过类型来访问
// console.log(p1.country) //错误
console.log(p1.name)
console.log(Person.name)