Angular

Angular学习笔记

1-angular环境搭建

1.安装cnpm

1
2
安装cnpm
参考阿里淘宝npm镜像,网址:https://developer.aliyun.com/mirror/NPM?from=tnpm

美女

1.1 npm配置全局下载位置和cache位置:

查看全局下载路径

1
npm config get prefix

配置全局下载路径

1
npm config set prefix "E:\NodeJS_WorkSpace\npm\npm_global"

将全局下载路径设置到PATH环境变量,以便直接使用cnpm、ng等下载下来的命令

查看cache路径

1
npm config get cache

配置cache路径

1
npm config set cache "E:\NodeJS_WorkSpace\npm\npm_cache"

查看全局安装

1
npm ls -g -depth 0

卸载angular

1
npm uninstall -g @angular/cli

查看所有配置

1
npm config list

修改registry

(默认为https://registry.npmjs.org/)

1
npm config set registry https://registry.npm.taobao.org

本地私仓路径(group)

http://192.168.29.141:8081/repository/npm-group/

本地私仓路径(hosted)

http://192.168.29.141:8081/repository/npm-hosted/

本地私仓路径(taobaoProxy)

http://192.168.29.141:8081/repository/npm-taobao/

regitry修改为原来的资源库

1
npm config set registry https://registry.npmjs.org/

1.2 使用命令行安装定制的cnpm

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

2.安装angular脚手架

使用 npm 或 cnpm 命令安装angular/cli

1
npm install -g @angular/cli

或者

1
cnpm install -g @angular/cli

安装完成后,通过查看版本号检查是否安装成功

在项目外使用ng v得到的是全局的angular脚手架版本

在项目文件夹中使用ng v得到的是该项目的angluar脚手架和angular及其他依赖的版本

1
ng v

2-新建angular项目

新建Angular项目

1 创建一个工作空间文件夹
2 命令行 cd 到这个文件夹
3 使用命令创建一个项目

1
2
3
4
5
6
7
8
9
10
11
12
13
# 直接安装

ng new test01

# 只创建项目,不安装依赖

ng new test01 --skip-install

# 或者 ng new test01 --skipInstall

# 不初始化git, 简写 -g

ng new test01 --skipGit

4 选择是否需要增加路由
5 选择项目使用的是css还是指定的预处理器:CSS、SCSS、SASS、LESS、Stylus
6 Angular自动创建项目文件
7 Angular创建文件后,会自动执行 npm i 安装 package.json中的依赖,可以使用ctrl + c强制结束该步骤
8 进入到项目文件夹,使用命令安装依赖

1
2
3
cd test01

cnpm install

9 安装好依赖后,编译并启动项目

1
2
3
--open 选项会自动打开浏览器,简写 -o ,并访问 http://localhost:4200/

--port 选项可以设置监听的端口号

出现的问题:ng命令报错

如果在项目中使用ng命令出现如下报错:

1
ng:无法加载文件ng.ps1,因为在此系统上禁止运行脚本.

则需要修改计算机的执行策略:

1 使用管理员身份打开PowerShell
2 执行如下命令

1
set-ExecutionPolicy RemoteSigned

3 根据提示,输入A

1
2
3
4
5
6
[Y]
[A] 全是
[N] 否(默认值)
[L] 全否
[S] 暂停
[?] 帮助

4 使用命令查看是否修改成功

1
get-ExecutionPolicy

前后端分离项目配置浏览器跨域

Angular项目调用后端项目接口时会涉及跨越问题,需要配置谷歌浏览器跨域:

1 创建一个文件夹,作为谷歌浏览器的跨域用户的数据文件夹
2 配置快捷方式的目标,添加参数:

允许跨域

1
--disable-web-security

跨域用户的数据文件夹

1
--user-data-dir 
1
"C:\Program Files(x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir=D:\PC_Document\GoogleData\CrossDomainUser

3 启动该快捷方式,即会以一个新用户启动谷歌浏览器,新用户的产生的浏览数据保存在指定的文件夹中,且该快捷方式允许跨域请求。

3-文件结构

Angular项目文件结构

● e2e文件夹
在e2e/下是端到端(End-to-End)测试

● node_modules文件夹
cnpm install安装的package.json定义的第三方模块都放在node_modules文件夹

● src文件夹
项目的所有的文件得放在src里面

○ app文件夹
app文件夹存放组件,以及app.module.ts定义根模块

  • app.components.css
  • app.components.ts
  • app.components.html

app.components.css、app.components.ts、app.components.html 组成根组件

  • app.components.spec.ts
  • app.module.ts
    根模块

○ assests文件夹
assests文件夹静态资源

○ environments文件夹
这个文件夹中包括为各个目标环境准备的文件

○ favicon.ico
项目图标

○ index.html
主页面

○ main.ts
应用的主要入口点

○ polyfills.ts
填充库(polyfill)能帮助我们把这些不同点进行标准化

○ styles.css
这里是定义的全局样式

○ test.ts
单元测试的主要入口点

● .editorconfig
编辑器的一个简单配置文件

● .gitignore
Git配置的忽略文件

● angular.json
angular的配置文件

● browserslist
Angular支持的浏览器的配置文件

● karma.conf.js
给Karma的单元测试配置

● package.json
npm配置文件

● README.md
项目的基础文档,说明文档

● tsconfig.app.json
TypeScript编译器的配置

● tsconfig.json
TypeScript编译器的配置

● tsconfig.spec.json
TypeScript编译器的配置

● tslint.json
给TSLint和Codelyzer的配置信息,Lint功能可以帮你保持代码风格的统一

4-组件

组件

组件控制屏幕上被称为视图的一小片区域。

组件由业务逻辑(.ts)、页面模板(.html)、样式(.css/.less等)组成

angular创建组件后会自动更新,不需要重启项目

根组件

  • app.component.html
  • app.component.ts
  • app.component.css

创建组件

使用angular的命令创建组件,参考链接:https://cli.angular.io/

1
2
3
4
5
6
7
8
9
10
11
cd test01

# 在src/app文件夹中生成一个components文件夹,在该文件夹下创建一个news组件,并自动在根组件app.module.ts中引入该组件

ng generate component components/news

# 或者简写为

ng g component components/news


创建的组件中包含4个文件:

  • xxx.component.css 样式文件(如果选了sass/scss/less等预编译,会生成相对应的样式文件)
  • xxx.component.html 渲染的html模板
  • xxx.component.ts 组件typescript文件
  • xxx.component.spec.ts 测试用的ts文件,可删除

其中,xxx.component.ts文件内容如下:(以search组件的search.component.ts为例)

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
// 从angular核心库中导入Component符号

import { Component, OnInit } from '@angular/core';

// 组件装饰器,声明下面的类为一个组件

@Component({

selector: 'app-search', // 是一个css选择器,一旦模板HTML中找到这个选择器对应的标签,就创建并插入该组件的一个实例的视图。即其他组件html渲染时引入该组件视图的标签名

templateUrl: './search.component.html', // 该组件的html模板文件相对于这个组件文件的地址。还可以用template属性的值来提供内联的html模板。这个模板定义了该组件的宿主视图

styleUrls: ['./search.component.css']

// providers:[HeroService] ,当前组件所需的服务的一个数组。

})

export class SearchComponent implements OnInit {

constructor() { }

ngOnInit(): void {

}

}

引入组件

如果是通过命令创建的组件,创建的组件会自动被进行引入到根模块app.module.ts中。

如果是手工创建的组件,使用时需要引入到app.module.ts中

1
2
3
4
5
6
7
8
9
10
11
12
// 在根模块app.module.ts的头部使用import引入创建的模块

import { NewsComponent } from './components/news/news.component';

// 在根模块app.module.ts中,@NgModule的declarations中加入该组件

@NgModule({
declarations: [
AppComponent, NewsComponent
],
// ....
})

调用组件

如果需要在其他组件中调用刚刚创建的新闻组件,则在组件的html中需要引用的位置加入组件名称标签

1
2
<!-- news.component.ts文件中的@Component装饰器的selector的值 -->
<app-news></app-news>

可以通过组件扩展html的标签

5-组件中的模板合成

组件中的模板

组件ts的class中定义的变量,在组件内的html中可以直接使用双大括号进行引用

绑定数据

./src/app/components/home/home.component.ts

1
2
3
4
5
6
7
8
9
// .......
export class HomeComponent implements OnInit {
title = '我是一个home组件'; // 定义一个类变量,不加修饰符默认为public。
public student:object = {
userName:'张三',
age:15
}
// ..........
}

./src/app/components/home/home.component.html

1
2
3
4
5
6
<!-- 使用双大括号引用组件内变量 -->
<h2>{{title}}</h2>
<h2>
<!-- 对象类型的也可以进行渲染 -->
{{student.userName}}
</h2>

ts中属性的值也可以在构造函数中进行赋值

1
2
3
4
5
public msg:string;
constructor() {
this.msg = '这是msg';
console.log('studet.age=' + this.student.age);
}

绑定到html属性

1
2
3
4
5
6
7
8
9
10
11
12
<div title='这是一个静态的title属性'>
test1
</div>

<!-- 使用中括号,将ts中的msg变量绑定到title属性中 -->
<div [title]='msg'>
test2
</div>

<!-- 使用bind-前缀绑定属性 -->
<img bind-src='itemImageUrl'>
<!-- 等同于 <img [src]='itemImageUrl'> -->

绑定html代码

在ts中定义属性:

1
public content:string = '<h2>这是一段html代码</h2>';

在html中获取content变量,并按html代码进行解析

不管是否为innerHTML属性,angular都不允许带有script标签的html泄露到浏览器中。

1
<div [innerHTML]='content'></div>

进行简单运算

1
2
3
4
<div>
计算 1+2={{1+2}}
计算 3+4 = {{ sum(3,4) }}
</div>

在ts中定义sum方法

1
2
3
sum(a, b) {
return a+b;
}

数组循环

普通循环

在ts中定义一个数组变量arr、newsList

1
2
public arr:string[] = ['111', '222', '333']; 
public newsList:Array<string> = ['第一个新闻','第二个新闻','第三个新闻'];

在html中使用 ng-for 循环arr、newsListt变量:

1
2
3
4
5
6
7
8
9
10
11
<ol>
<!-- *ngFor="let 数组子项 of 数组变量" -->
<li *ngFor="let item of arr">
{{item}}
</li>
</ol>
<ol>
<li *ngFor="let item of newsList">
{{item}}
</li>
</ol>

对象循环

在ts中定义一个数组变量userList

1
2
3
4
5
6
7
8
9
10
public userList:any[] = [{
name:'张三',
age:12
}, {
name:'李四',
age:18
},{
name:'王五',
age:20
}];

在html中使用 ng-for 循环userList变量:

1
2
3
4
5
<ol>
<li *ngFor="let item of userList">
{{item.name}} 今年 {{item.age}} 岁
</li>
</ol>

循环嵌套

在ts中定义carsList变量

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
public carsList:any[] = [{
cate:'宝马',
list:[{
title:'宝马x1',
price:'30万'
},{
title:'宝马x2',
price:'32万'
},{
title:'宝马x3',
price:'40万'
}]
},{
cate:'奥迪',
list:[{
title:'奥迪q1',
price:'10万'
},{
title:'奥迪q2',
price:'22万'
},{
title:'奥迪q3',
price:'30万'
}]
}];


在html中使用 ng-for 遍历汽车品牌,然后继续使用 ng-for 嵌套循环每个品牌的车型

1
2
3
4
5
6
7
8
9
10
<ul>
<li *ngFor="let item of carsList">
<h2>{{item.cate}}</h2>
<ol>
<li *ngFor="let car of item.list">
{{car.title}}价格:{{car.price}}
</li>
</ol>
</li>
</ul>

显示数组元素的索引

快捷方式 ng-for-index

在ts中定义数组变量

1
2
3
4
5
6
7
8
9
10
public cars:any[] = [{
title: '第一个新闻',
desc: 'aaa'
},{
title: '第二个新闻',
desc: 'bbb'
},{
title: '第三个新闻',
desc: 'ccc'
}];

在html中引入数组

1
2
3
4
5
6
<ul>
<!-- 将索引赋值给key,索引从0开始 -->
<li *ngFor="let item of cars; let key = index">
{{key}} : {{item.title}}
</li>
</ul>

模板引用变量

使用井号将一个dom元素声明为一个模板引用变量,该变量可以在html模板中直接使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<label>Type something:
<!-- 此处的customerInput.value中的customerInput不是ts中定义的变量,而是前面#customerInput声明的input本身 -->
<input #customerInput>{{customerInput.value}}
</label>

<!-- 将模板引用变量#heroForm传递给ts组件 -->

<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>

<!-- 定义的#phone模板引用变量,在整个html模板内都可以使用 -->
<input #phone placeholder="phone number" />
<button (click)="callPhone(phone.value)">Call</button>

<!-- 也可以使用ref-前缀代替井号 -->
<input ref-fax placeholder="fax number" />
<button (click)="callFax(fax.value)">Fax</button>

类型转换函数

有时候,绑定表达式可能会在AOT编译时报类型错误,并且它不能或很难指定类型,要消除这种报错,可以使用$any()转换成any类型

1
<p>The item's undeclared best by date is:         {{$any(item).bestByDate}}</p>

引入图片

引入静态资源图片

1 在静态资源文件夹assets创建文件夹images,将要引入的图片放置在assets/images文件夹中

美女

2 在html中引入图片

1
<img src="assets/images/Koala.jpg" alt="考拉" />

加载ts中引入的其他网站图片

1 在ts中定义图片路径变量

1
public picUrl:string = 'https://dss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/super/crop=0,0,1280,800/sign=4c135e228c8ba61ecba1926f7c04bb3a/4a36acaf2edda3cc81ffe0c80fe93901213f923b.jpg';

2 在html中引入该变量

1
<img [src]="picUrl" alt="背景图" />

条件判断

对ts中的布尔变量做判断

1 在ts中定义boolean类型的变量

1
public picFlag:boolean = true;

2 在html使用 ng-if 进行判断

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 当picFlag为true时展示 -->

<div *ngIf="picFlag">
<img src="assets/images/Koala.jpg" />
</div>

<!-- 当picFlag为false时展示 -->

<div *ngIf="!picFlag">
<img src="assets/images/Lighthouse.jpg">
</div>


对表达式做判断

1 在ts中定义数组

1
2
3
4
5
6
7
8
9
10
public cars:any[] = [{
title: '第一个新闻',
desc: 'aaa'
},{
title: '第二个新闻',
desc: 'bbb'
},{
title: '第三个新闻',
desc: 'ccc'
}];

2 在css文件中定义一个红色class

1
2
3
.red{
color: red;
}

3 在html中遍历数组,对下标为1的值标记为红色

1
2
3
4
5
6
<ul>
<li *ngFor="let item of cars; let key = index">
<span *ngIf="key == 1" class="red"> {{key}} : {{item.title}}</span>
<span *ngIf="key != 1"> {{key}} : {{item.title}}</span>
</li>
</ul>

switch-case语句

1 在ts中定义一个变量

1
public orderStatus:number = 1;

2 在html中使用switch-case对orderStatus进行判断

快捷方式 ng-switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<span [ngSwitch]="orderStatus">
<p *ngSwitchCase="1">
已支付
</p>
<p *ngSwitchCase="2">
已确认订单
</p>
<p *ngSwitchCase="3">
已发货
</p>
<p *ngSwitchCase="4">
已确认收货
</p>
<p *ngSwitchDefault>
无效状态
</p>
</span>

ngClass的使用

使用ngClass定义要使用的样式

1 在css文件中定义相关样式

1
2
3
4
5
6
7
8
9
10
.red {
color: red;
}
.blue {
color: blue;
}
.orange {
color: orange;
}

2 在html中使用ngClass决定要使用的class样式

1
2
3
4
5
6
<div>
<!-- 使用class='red'样式,不使用class='blue'样式 -->
<span [ngClass]="{'red': true, 'blue': false}">
ngClass测试
</span>
</div>

使用ngClass获取ts中的boolean变量改变样式

1 在ts中定义boolean类型变量

1
public colorFlag:boolean = false;

2 在html中获取colorFlag的值

1
2
3
4
5
6
7
<div>
<span [ngClass]="{'red': colorFlag, 'blue': !colorFlag}">
ngClass测试
<!-- colorFlag为true时,class='red';
colorFlag为false时,class='blue' -->
</span>
</div>

获取ts中的object变量改变样式

类似绑定数据到html属性

1 在ts中定义object类型变量

1
2
3
4
public classDefine:object = {
'orange':true,
'blue':false
}

2 在html中将获取ts变量

1
2
3
4
5
<div>
<span [ngClass]="classDefine">
ngClass测试
</span>
</div>

1
2
3
4
5
<div>
<span [class]="classDefine">
ngClass测试
</span>
</div>

使用class进行样式判断

当hero对象等于选中的selectedHero对象时,class为.selected

1
<li  [class.selected]="hero === selectedHero"></li>

ngStyle的使用

使用ngStyle定义一个普通样式

1
2
3
4
5
6
7
<p [ngStyle]="{'color': 'red'}"> 
测试ngStyle
</p>
<!-- 等同于下面 -->
<p style="color: red">
测试ngStyle
</p>

使用ngStyle引入ts中的样式变量

1 在ts中定义样式变量

1
public styleColor:string = 'red';

2 在html中引入该样式变量

1
2
3
<p [ngStyle]="'color' : styleColor">
测试ngStyle
</p>

管道

1 在ts中定义一个日期变量

1
public today = new Date();

2 在html中直接引入,并加入管道对日期格式化

1
2
3
4
<p>
<!-- 输出格式为:Tue Apr 28 2020 15:43:04 GMT+0800 (中国标准时间) -->
{{today}}
</p>
1
2
3
4
<p>
<!-- 输出格式为:2020-04-28 15:45:55 -->
{{today | date:'yyyy-MM-dd HH:mm:ss'}}
</p>

3 Angular内置了一些管道,比如DatePipe、UpperCasePipe、LowerCasePipe、CurrencyPipe、PercentPipe。也可以自定义管道。多个管道也可以串联使用。

绑定事件

1 在html中绑定事件

1
2
3
<button (click)='runTest()'> 
测试方法
</button>

2 在ts中添加runTest方法

1
2
3
runTest():void {
alert('测试方法');
}

3 绑定keyDown事件

1
<input (keydown)='keydown=($event)' />

4 在ts中添加keydown方法

1
2
3
4
5
6
7
8
9
keydown(e):void {
console.log(e);
// e.keyCode获取按下的键值
// e.target获取当前dom节点,即input框
// 此处的dom变量必须声明为any类型,否则会报错
let dom:any = e.target;
dom.style.color = red;
// e.target.value获取input框的value
}

双向数据绑定MVVM

前端修改的数据,绑定的后台变量会跟着修改;(M到V)

后台变量修改,前台绑定的模板跟着修改;(V到M)

双向数据绑定只能作用于表单

1 在app.module.ts中引入FormsModule模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// .....
// 引入FormsModule模块
import {FormsModule} from '@angular/forms';
//.....
@NgModule({
declarations: [
AppComponent
// ......
],
imports: [
BrowserModule,
// 在此处加入FormsModule模块
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }


2 在html中使用ngModel实现双向绑定

1
2
3
4
5
6
7
8
9
10
<p>
MVVM测试
</p>
<!-- 改变该输入框的值,绑定的后台title的值也会跟着改变 -->
<input [(ngModel)]="title" />
<br>
<!-- 实时显示后台title变量的值 -->
{{title}}
<br>
<button (click)='updateTitle()'>更新title</button>

3 在ts中定义title变量

1
2
3
4
public title:string = '原来的title';
updateTitle():void{
this.title = '修改后的title';
}

6-表单操作

表单双向数据绑定

1 在html中定义表单

1
<h2>人员登记系统</h2>
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
     <div class="people_list">
<ul>
<!-- 普通文本框的双向数据绑定 -->
<li>姓名:
<input type="text" id='username' [(ngModel)]="peopleInfo.username" class='form-input'/>
</li>

<!-- 单选框的双向数据绑定 -->
<li>
性别:
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="radio" name="sex" id="sex1" value='1' [(ngModel)]="peopleInfo.sex"><label for="sex1"></label>
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="radio" name="sex" id="sex2" value='2' [(ngModel)]="peopleInfo.sex"><label for="sex2"></label>
</li>

<!-- 下拉框的双向数据绑定 -->
<li>
城市:
<select name="city" id="city" [(ngModel)]="peopleInfo.city">
<option [value]="item" *ngFor="let item of cityList"> {{ item }} </option>
</select>
</li>

<!-- 复选框的双向数据绑定 -->
<li>
爱好:
&nbsp;&nbsp;
<span *ngFor="let item of peopleInfo.hobby; let key=index">
<input type="checkbox" name="hobby" [id]="'check' + key" [(ngModel)]='item.checked'> <label [for]="'check' + key"> {{ item.title }} </label>
&nbsp;&nbsp;
</span>
</li>

<!-- 多行文本框的双向数据绑定 -->
<li>
备注:
<textarea name="mark" id="mark" cols="30" rows="10" [(ngModel)]='peopleInfo.mark'></textarea>
</li>
</ul>

<br>
<br>
<br>
<br>
<br>
<br>
<!-- 以json样式实时展示peopleInfo对象的内容 -->
1
<button (click)="doSubmit()">获取表单的值</button>
  1. 绘制css样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
h2{
text-align: center;
}

.people_list {
width: 400px;
margin: 20px auto;
padding: 20px;
border: 1px solid #eee;
}

.people_list li {
height: 50px;
line-height: 50px;
}

.people_list li .form-input {
width: 300px;
height: 28px;
}

3 编写ts

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
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

// 定义peopleInfo对象,用于存放表单数据

public peopleInfo:any = {
username: '',
sex:'1',
city:'上海',
hobby: [
{
title: '吃饭',
checked: false
},
{
title: '睡觉',
checked: false
},
{
title: '敲代码',
checked: true
}
],
mark:''
}

// 作为下拉框的选项

public cityList:string[] = ['北京', '上海', '深圳'];

constructor() { }
ngOnInit(): void { }

doSubmit():void {
console.log(this.peopleInfo);
}
}


7-待办事项案例

待办事项案例

1 绘制html页面

1
<h2>todolist</h2>
1
2
3
<div class="todolist">
<input class="form-input" type="text" [(ngModel)]="keyword" (keyup)='doAdd($event)'>
<hr>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h2>待办事项</h2>

<ul>
<li *ngFor="let item of todoList; let key=index;" [hidden]='item.status==1'>
<input type="checkbox" name="todolist" id="todolist" [(ngModel)]='item.status'>
{{ item.title }} -------------------
<button (click)='deleteData(key)'>X</button>
</li>
</ul>

<h2>已完成事项</h2>
<ul>
<li *ngFor="let item of todoList; let key=index;" [hidden]='item.status==0'>
<input type="checkbox" name="todolist" id="todolist" [(ngModel)]='item.status'>
{{ item.title }} -------------------
<button (click)='deleteData(key)'>X</button>
</li>
</ul>
</div>

2 绘制less样式

1
2
3
4
5
6
7
8
9
10
11
12
13
h2 {
text-align: center;
}

.todolist {
width: 400px;
margin: 20px auto;
.form-input {
margin-bottom: 20px;
width: 300px;
height: 32px;
}
}

3 编写typescript

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
import { Component, OnInit } from '@angular/core';
import { element } from 'protractor';

@Component({
selector: 'app-todolist',
templateUrl: './todolist.component.html',
styleUrls: ['./todolist.component.css']
})
export class TodolistComponent implements OnInit {

public keyword:string;
public todoList:any[] = [];

constructor() { }

ngOnInit(): void {
}

doAdd(e){
// 监控按下的键是否为回车键
if(e.keyCode != 13) {
return;
}
if(this.todoList.indexOf(this.keyword) < 0) {
if(this.todolistHaskeyword(this.todoList, this.keyword)) {
alert('该待办事项已录入');
return;
}
// 将keyword添加到todoList中
this.todoList.push({
title: this.keyword,
status: 0 // 0.待办事项;1.已完成事项
});
}
this.keyword = '';
}

deleteData(key) {
// 从todoList中移除key位置的1个元素
this.todoList.splice(key, 1);
}

// 判断对象数组中是否存在某个元素
todolistHaskeyword(todolist:any[], keyword:any) {
let result = false;
todolist.forEach(element => {
if(element.title == keyword) {
// forEach的值不能return到外面,所以此处不能直接写: return true;
result = true;
}
});
return result;
}
}

8-服务

服务

angular中,组件之间不能相互调用。可以把公共部分封装成服务,然后在组件中调用服务。

● 所有的组件都可以调用服务;
● 服务不能调用组件;
● 组件之间也不能相互调用组件的方法;
● 组件之间可以父子组件传值;
● 服务和服务之间可以相互调用;

创建服务

1 在src/app下创建services文件夹,并在该文件夹中创建storage服务

创建组件时,如果使用 ng g component compoents/search ,会创建components文件夹后,再在文件夹内创建search文件夹来存放组件;

创建服务时,使用 ng g service services/storage ,会创建services文件夹后,直接在services文件夹中生成服务的程序

新增的服务包含以下文件:

  • xxx.service.ts 服务的ts文件

  • xxx.service.spec.ts 测试文件,可删除

其中,xxx.service.ts内容如下:(以storage服务的storage.service.ts文件为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { Injectable } from '@angular/core';

// 要把一个类定义为服务,需要使用@Injectable装饰器来提供元数据,以便让Angular可以把它作为依赖注入到组件中。
// 服务可以把自己的元数据注册为提供者,这样可以让自己随处可用。或者,你也可以为特定的模块或组件注册提供者。
// 要注册提供者,就要在服务的@Injectable()装饰器中提供他的元数据,或者在@NgModule()或@Component()的元数据providers数组中。
// 默认情况下,angular CLI的 `ng generate service` 命令会在@Injectable()装饰器中提供元数据来把它注册到根注入器中: providedIn: 'root'
// 当你在根一级提供服务时,该服务为单例。这种在@Injectable元数据中注册提供者的方式还让Angular能够通过移除那些从未被用过的服务来优化大小
// 当在特定NgModule中,使用@NgMoudle中的providers属性注册提供者时,该服务的同一个实例对该NgModule的所有组件可用
// 当在特定Component中,使用@Component的providers属性注册提供者时,会为该组件的每一个新实例提供一个服务新实例。
@Injectable({
providedIn: 'root'
})
export class StorageService {

constructor() { }

// 编写逻辑
get() {
return 'test service';
}
}

2 在app.module.ts中加入该服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 使用import引入服务
import { StorageService } from './services/storage.service'

// declarations可声明对象表: 属于本NgModule的组件、指令、管道
// imports: 导入本模块中的组件模板所需的类的其他模块
// providers: 本模块向全局服务中贡献的服务的创造器,这些服务能被本应用中的任务部分使用(也可以在组件级别指定服务提供者,通常指定组件级别)
// bootstrap: 应用的主视图,根组件。它是应用中所有其他视图的宿主。只有根模块才应该设置bootstrap属性
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule
],
// 在@NgModule的providers中添加服务
providers: [StorageService],
bootstrap: [AppComponent]
})
export class AppModule { }

使用服务方式

在构造方法中使用依赖注入

示例:在todolist模块中引入storage服务,编辑todolist.components.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';
// 引入服务
import { StorageService } from '../../services/storage.service'

@Component({
selector: 'app-todolist',
templateUrl: './todolist.component.html',
styleUrls: ['./todolist.component.css']
})
export class TodolistComponent implements OnInit {

// 在构造方法中自动注入对象(不加public时,为constructor的方法内部变量。加了public为class的变量,可在class中任意地方使用this.storageService调用)
constructor(public storageService: StorageService) {
let s = this.storageService.get();
console.log(s);
}
}

9-angular中dom操作

angular中dom操作

ngOnInit()方法

ngOnInit()方法是组件和指令初始化完成,并不是真正的dom加载完成。

示例html模板:

1
2
3
4
5
6
<div id="box1">
this is text1
</div>
<div id="box2" *ngIf="flag">
this is text2
</div>

示例typescript程序:

1
2
3
4
5
6
7
8
9
10
11
ngOnInit(): void {
// box1不涉及到angular组件模板合成,可以正常获取操作
let box1:any = document.getElementById('box1');
console.log(box1.innerHTML);
box1.style.color = 'red';

// box2中含有ngIf语句,在执行ngOnInit时box2节点未渲染,box2此处获取不到
let box2:any = document.getElementById('box2');
console.log(box2.innerHTML);
box2.style.color = 'yellow';
}

ngAfterViewInit()方法

视图加载完毕后执行

实例typescript程序:

1
2
3
4
5
6
7
8
9
10
11
12
// 真正的dom加载完成
ngAfterViewInit(): void {
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
//Add 'implements AfterViewInit' to the class.
let box1:any = document.getElementById('box1');
console.log(box1.innerHTML);
box1.style.color = 'red';

let box2:any = document.getElementById('box2');
console.log(box2.innerHTML);
box2.style.color = 'yellow';
}

ViewChild

在ts中,可以使用原生js的document.getElementById获取标签,也可以使用ViewChild获取标签和子组件

1 在组件的html模板中定义div、子组件,并配置 #名称

1
2
3
4
5
6
7
<!-- 子组件,命名为myHeader -->
<app-header #myHeader></app-header>

<!-- div标签命名为myBox -->
<div #myBox>
test myBox节点
</div>

2 在组件的ts文件中获取div和子组件,并调用子组件的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 加入ViewChild
import { Component, OnInit, ViewChild } from '@angular/core';

@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.less']
})
export class NewsComponent implements OnInit {

// 获取myBox
@ViewChild('myBox') myBox:any;
// 获取myHeader
@ViewChild('myHeader') myHeader:any;

ngAfterViewInit(): void {
// 通过this.myBox.nativeElement获取dom节点
console.log(this.myBox.nativeElement.innerHTML);
this.myBox.nativeElement.style.color = 'red';
// 调用myHeader子组件的run方法
this.myHeader.run();
}

}

3 也可以在父组件中使用ViewChild获取子组件对象

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
import { AfterViewInit, ViewChild } from '@angular/core';
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';

@Component({
selector: 'app-countdown-parent-vc',
template: `
<h3>Countdown to Liftoff (via ViewChild)</h3>
<button (click)="start()">Start</button>
<button (click)="stop()">Stop</button>
<div class="seconds">{{ seconds() }}</div>
<app-countdown-timer></app-countdown-timer>
`,
styleUrls: ['../assets/demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {

@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;

seconds() { return 0; }

ngAfterViewInit() {
setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
}

start() { this.timerComponent.start(); }
stop() { this.timerComponent.stop(); }
}

10-父子组件通讯

父子组件通讯

非父子组件间变量通讯,可以存入window.localStorage中;

或者定义成服务;

子组件获取父组件变量、方法、父组件对象

1.父组件typescript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Component, OnInit, ViewChild } from '@angular/core';

@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.less']
})
export class NewsComponent implements OnInit {

// 定义变量msg、data
public msg:string = '父组件msg';
public data:string = '父组件data';

constructor() { }

ngOnInit(): void {
}

// 定义方法run
run() {
console.log('父组件的run方法执行了');
}
}

2 配置父组件的html模板

1
2
3
4
5
6
<!-- 将msg/data变量赋值给子组件的msg/data变量 -->
<!-- 将父组件的run方法对象赋值给子组件的run变量 -->
<!-- 将父组件对象本身赋值给子组件的news变量 -->
<!-- [msg]为子组件定义的@Input();'msg'为父组件的msg变量-->
<app-header [msg]='msg' [data]='data' [run]='run' [news]='this'></app-header>
<div></div>

3 在子组件中获取相应变量

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
// 引入Input装饰器
import { Component, OnInit, Input } from '@angular/core';

@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.less']
})
export class HeaderComponent implements OnInit {

// 获取父组件传入的内容
@Input() msg:string;
@Input() data:string;
@Input() news:any;
@Input() run:any;

ngAfterViewInit(): void {

// 调用父组件传来的run方法对象
this.run();
console.log('------------');
// 通过传进来的父组件本身调用其run方法
this.news.run();
}

}

4 在子组件上展示父组件的变量值

1
2
3
4
5
6
<div>
{{data}}
</div>
<div>
{{msg}}
</div>

5 可以在setter上添加@Input()截听输入属性值的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-name-child',
template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
private _name = '';

@Input()
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}
}

在子组件中主动调用父组件方法

通过@ViewChild可以让父组件主动调用子组件的方法、获取子组件的内容;

通过@Output()、EventEmitter可以让子组件主动调用父组件的方法,主动广播数据给父组件;

1 在子组件typescript中定义要广播的事件变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 引入Output、EventMitter
import { Component, OnInit, EventEmitter, Output } from '@angular/core';

@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.less']
})
export class HeaderComponent implements OnInit {

// 声明outputdata变量为eventemitter,泛型为emit载荷的类型
@Output() outputdata = new EventEmitter<string>();

sendParent() {
// 向父组件广播数据:'子组件的outputdata传入的数据'
this.outputdata.emit('子组件的outputdata传入的数据');
}

}

2 在子组件html模板中配置按钮触发sendParent方法

1
2
3
<div>这是header子组件</div>
<button (click)='sendParent()'>调用方法给父组件广播数据</button>
<hr>

3 在父组件的typescript中配置run方法,用于子组件主动调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, OnInit} from '@angular/core';

@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.less']
})
export class NewsComponent implements OnInit {

// 传入的变量e即为子组件广播给父组件的数据
run(e) {
console.log('这是父组件的run方法');
console.log(e);
}
}

4 在父组件html模板中配置子组件和子组件的output

1
2
3
4
5
<!-- outputdata为子组件@Output的变量名,run为父组件的待调用方法,$event为子组件outputdata.emit的广播内容 -->
<app-header (outputdata)='run($event)'></app-header>
<div>
这是父组件
</div>

11-生命周期钩子

生命周期钩子

美女

每个生命周期钩子接口都有唯一的一个钩子方法,钩子方法的名称是由钩子接口名加上ng前缀构成。比如OnInit接口的钩子方法叫做ngOnInit。

钩子接口是可选的:在组件中可以在类上实现生命周期钩子接口,再实现生命周期钩子接口中对应的钩子方法。也可以直接在类中实现生命周期钩子方法,而不在类上声明对应的声明周期钩子接口。Angular一旦发现钩子方法被定义了就会调用它们,有没有接口无所谓。

只有在指令/组件中定义过的那些钩子方法才会被Angular调用。

钩子方法 用途及时机
ngOnChanges() 当 Angular(重新)设置数据绑定输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
ngOnInit() 在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。在第一轮 ngOnChanges() 完成之后调用,只调用一次。
ngDoCheck() 检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。在每个变更检测周期中,紧跟在 ngOnChanges() 和 ngOnInit() 后面调用。
ngAfterContentInit() 当 Angular 把外部内容投影进组件/指令的视图之后调用。第一次 ngDoCheck() 之后调用,只调用一次。
ngAfterContentChecked() 每当 Angular 完成被投影组件内容的变更检测之后调用。ngAfterContentInit() 和每次 ngDoCheck() 之后调用
ngAfterViewInit() 当 Angular 初始化完组件视图及其子视图之后调用。第一次 ngAfterContentChecked() 之后调用,只调用一次。
ngAfterViewChecked() 每当 Angular 做完组件视图和子视图的变更检测之后调用。ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
ngOnDestroy() 每当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。在 Angular 销毁指令/组件之前调用。

12-RxJS

RxJS是一个库,它通过使用observable序列来编写异步和基于事件的程序。它提供了一个核心类型Observable,附属类型(Observer、Schedulers、Subjects)和受[Array#extras]启发的操作符(map、reduce、filter、every等),这些数组操作符可以把异步事件作为集合来处理。

RxJS是ReactiveX变成理念的JS版本。是一种针对异步数据流的编程。

它将一切数据,包括HTTP请求、DOM事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。

未使用RxJS时获取异步数据的方式

通过回调函数获取

1 新增一个request服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class RequestService {
constructor() { }
// 外部通过同步方式直接获取返回的数据
getData() {
return 'this is service data';
}
// 外部通过给getCallbackData传入回调函数获取name变量
getCallbackData(callbackFunction) {
setTimeout(() => {
let name = '张三';
callbackFunction(name);
}, 1000);
}
}

2 在app.module.ts中加入该服务
3 在testrequest组件中调用request服务的相关方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

// 注入服务
constructor(public requestService:RequestService) { }

ngOnInit(): void {
// 同步方法直接调用
let requestData = this.requestService.getData();
console.log(requestData);

// 通过回调函数获取getCallbackData方法的name变量
this.requestService.getCallbackData((data) => {
console.log(data);
});
}
}

通过Promise获取

1 修改request服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class RequestService {
constructor() { }
getData() {
return 'this is service data';
}
// 返回一个Promise对象,外部通过getCallbackData().then(resolve(name))进行调用
getCallbackData() {
return new Promise((resolve) => {
setTimeout(() => {
let name = '张三---Promise';
resolve(name);
}, 1000);
});

}
}

2 修改testrequest组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

constructor(public requestService:RequestService) { }

ngOnInit(): void {
let requestData = this.requestService.getData();
console.log(requestData);

// 通过Promise的then方法进行调用
this.requestService.getCallbackData().then((data) => {
console.log(data);
});
}

}

RxJS获取异步数据

写法类似Promise。

ES6的异步对象类型为Promise < == > RxJS中的异步对象类型为Observable;

ES6的Promise返回成功数据为resolve(数据) < == > RxJS中Observable返回成功数据为observe.next(数据);

ES6的Promise返回失败数据为reject(数据) < == > RxJS中Observable返回失败数据为observe.error(数据);

ES6中Promise的调用为then方法 < == > RxJS中Observable的调用为subscribe方法;

RxJS可以中途撤回、发射多个值、提供了多种工具函数等

获取异步数据

1 修改request服务

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
import { Injectable } from '@angular/core';

// 引入rsjs的Observable
// Angular中已经自带了RxJS,无需另外安装
import { Observable } from 'rxjs'

@Injectable({
providedIn: 'root'
})
export class RequestService {

constructor() { }

getData() {
return 'this is service data';
}

// 返回一个Promise对象,外部通过getCallbackData().then(回调函数(name))进行调用
getCallbackData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let name = '张三---Promise';
resolve(name);
// 失败时调用 reject('失败了');
}, 1000);
});
}

// 返回一个Observable对象,外部通过getRxjsData().subscribe(回调函数(name)) 进行调用
getRxjsData() {
return new Observable((observe) => {
setTimeout(() => {
let name = '张三---observe';
observe.next(name);
// 失败时调用:observe.error('失败了');
}, 1000);
});
}
}

2 修改testrequest组件

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
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

constructor(public requestService:RequestService) { }

ngOnInit(): void {
let requestData = this.requestService.getData();
console.log(requestData);

// 通过Promise的then方法进行调用
this.requestService.getCallbackData().then((data) => {
console.log(data);
});

// 通过Observable的subscribe方法调用
this.requestService.getRxjsData().subscribe((data) => {
console.log(data);
});
}
}

撤回订阅(中途撤回)

Promise创建之后,动作时无法撤回的。Observable不一样,动作可以通过unsubscribe()方法进行中途撤回

1 修改request服务,setTimeOut时间修改为3秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'

@Injectable({
providedIn: 'root'
})
export class RequestService {

constructor() { }

// 设置为3秒后执行
getRxjsData() {
return new Observable((observe) => {
setTimeout(() => {
let name = '张三---observe';
observe.next(name);
}, 3000);
});
}
}

2 修改testrequest组件,设置为获取异步对象之后1秒钟(request的3秒方法还未执行)便取消订阅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

constructor(public requestService:RequestService) { }

ngOnInit(): void {
// 将subscribe方法的返回结果赋值给sub变量
let sub = this.requestService.getRxjsData().subscribe((data) => {
console.log(data);
});

// 设置1秒钟后,sub变量调用unsubscribe取消订阅
setTimeout(() => {
sub.unsubscribe();
}, 1000);
}
}ty

订阅后多次执行

Promise不能多次执行,对于Promise来说,最终结果要么resolve(兑现),要么reject(拒绝),而且都只能触发一次,同一个Promise对象上多次调用resolve方法会抛出异常。

Observable可以不断地触发下一个值,就像next()这个方法名字所暗示的一样。

1 修改request服务,setTimeout改成setInterval(),实现多次执行observe.next方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs'

@Injectable({
providedIn: 'root'
})
export class RequestService {

constructor() { }

// setTimeOut改成setInterval,多次执行observe.next
getRxjsIntervalData() {
let count = 0;
return new Observable((observe) => {
setInterval(() => {
count++;
observe.next(count);
}, 3000);
});
}
}

2 修改testrequest组件,调用该服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

constructor(public requestService:RequestService) { }

ngOnInit(): void {
this.requestService.getRxjsIntervalData().subscribe((data) => {
console.log(data);
});
}
}

RxJS工具函数

Angular6之后使用以前的RxJS方法,必须安装rxjs-compat模块才可以使用map、filter方法。

Angular6之后官方使用的是RxJS6的新特性,所以官方给出了一个暂时延缓不需要修改rxjs代码的方法:

1
npm install rxjs-compat

本地使用Angular8、9,不需要另外安装rxjs-compat

示例代码:

1 编写request服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 加入需要用到的rxjs的工具函数操作符,例如map、filter等
import { filter,map } from 'rxjs/operators';

@Injectable({
providedIn: 'root'
})
export class RequestService {

constructor() { }

// 每隔2秒输出一个数,持续输出
getRxjsIntervalData() {
let count = 0;
return new Observable((observe) => {
setInterval(() => {
count++;
observe.next(count);
}, 2000);
});
}
}

2 编写testrequest组件

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
import { Component, OnInit } from '@angular/core';
import { RequestService } from '../../services/request.service';
import { filter, map } from 'rxjs/operators';

@Component({
selector: 'app-testreqesut',
templateUrl: './testreqesut.component.html',
styleUrls: ['./testreqesut.component.less']
})
export class TestreqesutComponent implements OnInit {

constructor(public requestService:RequestService) { }

ngOnInit(): void {
// 获取observe.next返回的操作流
let stream = this.requestService.getRxjsIntervalData();

// 为流添加pipe管道,在管道内加入map、filter方法
stream
.pipe(
// 仅输出偶数
filter((value:number) => {
if(value%2 == 0) {
return true;
}
}),
// 将value转换为value的平方进行输出
map((value:number) => value**2)
)
.subscribe((data) => {
console.log(data);
});
}
}

13-请求数据

Angular5.x以后,get、post和服务器交互使用的是HttpClientModule模块。

Get请求