Angular学习笔记 1-angular环境搭建 1.安装cnpm 1 2 安装cnpm 参考阿里淘宝npm镜像,网址:https:// developer.aliyun.com/mirror/ NPM?from=tnpm
1.1 npm配置全局下载位置和cache位置: 查看全局下载路径
配置全局下载路径
1 npm config set prefix "E:\NodeJS_WorkSpace\npm\npm_global"
将全局下载路径设置到PATH环境变量,以便直接使用cnpm、ng等下载下来的命令
查看cache路径
配置cache路径
1 npm config set cache "E:\NodeJS_WorkSpace\npm\npm_cache"
查看全局安装
卸载angular
1 npm uninstall -g @angular/cli
查看所有配置
修改registry
(默认为https://registry.npmjs.org/ )
1 npm config set registry https:
本地私仓路径(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:
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及其他依赖的版本
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 进入到项目文件夹,使用命令安装依赖
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 使用命令查看是否修改成功
前后端分离项目配置浏览器跨域 Angular项目调用后端项目接口时会涉及跨越问题,需要配置谷歌浏览器跨域:
1 创建一个文件夹,作为谷歌浏览器的跨域用户的数据文件夹 2 配置快捷方式的目标,添加参数:
允许跨域
跨域用户的数据文件夹
1 "C:\P rogram Files(x86)\G oogle\C hrome\A pplication\c hrome.exe" --disable-web-security --user-data-dir=D:\P C_Document\G oogleData\C rossDomainUser
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 import { Component, OnInit } from '@angular/core' ;@Component ({ selector: 'app-search' , templateUrl: './search.component.html' , styleUrls: ['./search.component.css' ] }) 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 import { NewsComponent } from './components/news/news.component' ;@NgModule ({ declarations: [ AppComponent, NewsComponent ], })
调用组件 如果需要在其他组件中调用刚刚创建的新闻组件,则在组件的html中需要引用的位置加入组件名称标签
可以通过组件扩展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 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 > <div [title ]='msg' > test2 </div > <img bind-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 > <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 > <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: <input #customerInput > {{customerInput.value}} </label > <form #heroForm (ngSubmit )="onSubmit(heroForm)" > ... </form > <input #phone placeholder ="phone number" /> <button (click )="callPhone(phone.value)" > Call</button > <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 <div *ngIf ="picFlag" > <img src ="assets/images/Koala.jpg" /> </div > <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
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 > <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测试 </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 > {{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); let dom:any = e.target; dom.style.color = red; }
双向数据绑定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 import {FormsModule} from '@angular/forms' ;@NgModule ({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
2 在html中使用ngModel实现双向绑定
1 2 3 4 5 6 7 8 9 10 <p > MVVM测试 </p > <input [(ngModel )]="title" /> <br > {{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 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 > 性别: <input type ="radio" name ="sex" id ="sex1" value ='1' [(ngModel )]="peopleInfo.sex" > <label for ="sex1" > 男</label > <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 > 爱好: <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 > </span > </li > <li > 备注: <textarea name ="mark" id ="mark" cols ="30" rows ="10" [(ngModel )]='peopleInfo.mark' > </textarea > </li > </ul > <br > <br > <br > <br > <br > <br >
1 <button (click )="doSubmit()" > 获取表单的值</button >
绘制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 { 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 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 ; } this .todoList.push({ title: this .keyword, status: 0 }); } this .keyword = '' ; } deleteData (key ) { this .todoList.splice(key, 1 ); } todolistHaskeyword (todolist:any [], keyword:any ) { let result = false ; todolist.forEach(element => { if (element.title == keyword) { 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内容如下:(以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 ({ 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 { StorageService } from './services/storage.service' @NgModule ({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule ], 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 { 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 { 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' ; }
ngAfterViewInit()方法
视图加载完毕后执行
实例typescript程序:
1 2 3 4 5 6 7 8 9 10 11 12 ngAfterViewInit(): void { 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 <app-header #myHeader > </app-header > <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 import { Component, OnInit, ViewChild } from '@angular/core' ;@Component ({ selector: 'app-news' , templateUrl: './news.component.html' , styleUrls: ['./news.component.less' ] }) export class NewsComponent implements OnInit { @ViewChild ('myBox' ) myBox:any ; @ViewChild ('myHeader' ) myHeader:any ; ngAfterViewInit(): void { console .log(this .myBox.nativeElement.innerHTML); this .myBox.nativeElement.style.color = 'red' ; 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 { public msg:string = '父组件msg' ; public data:string = '父组件data' ; constructor ( ) { } ngOnInit(): void { } run ( ) { console .log('父组件的run方法执行了' ); } }
2 配置父组件的html模板
1 2 3 4 5 6 <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 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 { this .run(); console .log('------------' ); 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 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 { @Output () outputdata = new EventEmitter<string >(); sendParent ( ) { 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 { run (e ) { console .log('这是父组件的run方法' ); console .log(e); } }
4 在父组件html模板中配置子组件和子组件的output
1 2 3 4 5 <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 (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); 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' ; } 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); 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' ;import { Observable } from 'rxjs' @Injectable ({ providedIn: 'root' }) export class RequestService { constructor ( ) { } getData ( ) { return 'this is service data' ; } getCallbackData ( ) { return new Promise ((resolve, reject ) => { setTimeout (() => { let name = '张三---Promise' ; resolve(name); }, 1000 ); }); } getRxjsData ( ) { return new Observable((observe ) => { setTimeout (() => { let name = '张三---observe' ; observe.next(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 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); this .requestService.getCallbackData().then((data ) => { console .log(data); }); 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 ( ) { } 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 { let sub = this .requestService.getRxjsData().subscribe((data ) => { console .log(data); }); 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 ( ) { } 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代码的方法:
本地使用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' ;import { filter,map } from 'rxjs/operators' ;@Injectable ({ providedIn: 'root' }) export class RequestService { constructor ( ) { } 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 { let stream = this .requestService.getRxjsIntervalData(); stream .pipe( filter((value:number ) => { if (value%2 == 0 ) { return true ; } }), map((value:number ) => value**2 ) ) .subscribe((data ) => { console .log(data); }); } }
13-请求数据
Angular5.x以后,get、post和服务器交互使用的是HttpClientModule模块。
Get请求