一.易疏漏知识点
-
使用Cli安装Angular项目但不导入对应依赖
ng new 项目名 --skip-install
-
项目结构
- e2e端对端测试文件
- node_modules依赖包
- src源码
- karma.conf.js测试文件
- polyfills.ts填充库文件,在angular加载之前首先加载
- test.ts测试的入口文件
- .editorconfig编辑器配置文件
- angular.json Angular配置文件
- tsconfig.json是Typescript的配置文件
-
ts文件中声明属性的方式
- public:属性前面不加任何类型则是public类型,在当前类、当前类子类及类外可访问
- protected:保护类型,只有在当前类和当前类的子类中可以访问
- private:私有类型,只有在当前类才可以访问这个属性
-
解析ts文件中定义的html代码段使用innerHTML属性,实例如下
- typescript段
msg = "<h1>这是一段测试</h1>"
- html段
<p [innerHTML]="msg"></p>
-
*ngSwitch条件判断语句
- 实例代码如下,当score为1时显示的是已支付,为2时显示订单已确认…
<ul [ngSwitch]="score"> <li *ngSwitchCase="1">已支付</li> <li *ngSwitchCase="2">订单已确认</li> <li *ngSwitchCase="3">已发货</li> <li *ngSwitchDefault>无效</li> </ul>
-
属性
[ngClass]/[ngStyle]
- ngClass使用:
[ngClass]="{'class名':boolean类型,'class名':boolean类型}"
- ngStyle使用:
[ngStyle]="{'style名':'style值'}"
- ngClass使用:
-
事件对象,在标签使用事件时传入
$event
- 接受后使用
e.target
可以获得对应的dom对象 - 接受后使用
e.target.value
可以获得input标签的值内容
- 接受后使用
-
双向数据绑定ngModel:只针对表单元素【MVVM模型,模型变了页面就变,页面变了数据就变】
- 使用ngModel绑定radio时,当ngModel绑定的值与input标签里的value值相同时即可选中
- 使用ngModel绑定checkbox时,当ngModel绑定的值是true时该多选框被选中,为false时该多选框没有选中
-
使用
[]
绑定数据时,如果想在ts数据前后添加内容使用字符串拼接的方式<input type="checkbox" [id]="'check'+key"/>
-
使用service服务
- 创建服务命令
ng g service serviceName
- 在NgModule的providers中依赖注入服务
- 在使用该服务的组件的构造方法参数中注入服务
- 创建服务命令
-
Angular中的Dom操作使用@ViewChild
-
注意:ngOnInit()方法是组件和指令初始化完成的周期钩子,不是真正Dom加载完成。ngAfterViewInit()方法是视图加载以后触发的方法,此时Dom已加载完成。
-
基本使用
-
定义标签
<div #test></div>
-
获取Dom节点
@ViewChild('test') test:ElementRef; //获取Dom节点的方法 ngAfterViewInit() { //通过nativeElement获取Dom节点 this.test.nativeElement; }
-
-
父子组件通过ViewChild调用子组件的方法**【用于获取子组件实例 】**
-
在父组件中给子组件定义一个名称
<app-header #headerChild></app-header>
-
引入@ViewChild
import {ViewChild} from '@angular/core';
-
将ViewChild和刚才的组件关联
@ViewChild('headerChild') header:any;
-
调用子组件
run() { this.header.testMethod();//testMethod方法是HeaderChild组件中的方法 }
-
-
-
父组件与子组件之间的通讯
-
父组件给子组件传值@Input
-
父组件调用子组件的时候传值在属性中
<app-header [msg]="msg"></app-header>
-
子组件通过@Input接受父组件传递的数据
export class HeaderComponent implements OnInit { @Input() msg:string; }
-
-
子组件通过@Output触发父组件的方法
-
子组件中实例化EventEmitter可以向父组件传递数据
@Output() private outer = new EventEmitter<string>();
-
子组件使用EventEmitter对象的emit方法可以传递实时广播
sendParent() { this.outer.emit('msg from child'); }
-
父组件调用子组件的时候接收事件,outer就是子组件的EventEmitter对象
<app-header (outer)="runParent($event)"></app-header>
-
父组件接收数据会调用runParent方法,此时可以拿到子组件数据
runParent(msg:string) { alert(msg); }
-
-
非父子组件通讯
- 公共的服务
- localStorage
- Cookie
-
-
Angular中的生命周期函数
- constructor:构造函数中除了使用简单的值对局部变量进行初始化之外,什么都不应该做
- ngOnChanges():当Angular(重新)设置数据绑定输入属性时响应。该方法接受当前和上一属性值的SimpleChanges对象当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit() 之前。
- ngOnInit():在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。在第一轮 ngOnChanges() 完成之后调用,只调用一次。使用 ngOnInit() 有两个原因: 1、在构造函数之后马上执行复杂的初始化逻辑。2、在 Angular 设置完输入属性之后,对该组件进行准备。有经验的开发者会认同组件的构建应该很便宜和安全。
- ngDoCheck():检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。在每个 Angular 变更检测周期中调用, ngOnChanges() 和 ngOnInit() 之后。
- ngAfterContentInit():当把内容投影进组件之后调用。第一次 ngDoCheck() 之后调用,只调用一次。
- ngAfterContentChecked():每次完成被投影组件内容的变更检测之后调用。ngAfterContentInit() 和每次 ngDoCheck() 之后调用。
- ngAfterViewInit():初始化完组件视图及其子视图之后调用。第一次 ngAfterContentChecked() 之后调用,只调用一次。
- ngAfterViewChecked():每次做完组件视图和子视图的变更检测之后调用。 ngAfterViewInit()和每次 ngAfterContentChecked() 之后调用。
- ngOnDestroy() :当 Angular 每次销毁指令/组件之前调用并清扫。在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。 在 Angular 销毁指令/组件之前调用。
二.异步处理方式
1.使用回调函数的方式
-
定义需要执行回调函数的方法
getCallbackData(cd) {//cd是回调函数 setTimeout(()=>{ var username = 'Jack'; cd(username);//等待异步方法执行时调用回调函数 },1000) }
-
调用方法时传入回调函数
this.getCallbackData((username:string)=>{ console.log(username);//传入的回调函数执行打印的功能 })
-
此时执行到调用时会打印
Jack
2.使用Promise对象获得异步方法的数据
-
定义需要执行回调函数的方法
getPromiseData() { return new Promise((resolve,reject)=>{ //resolve表示成功后执行的回调函数,reject表示失败后执行的回调函数 setTimeout(()=>{ var username = 'Jack'; resolve(username); },1000);//设置异步方法 }) }
-
调用方法时传入回调函数,使用promise获取异步数据
var promiseObject = this.getPromiseData();//获取到方法返回的Promise对象 promiseObject.then((data)=>{//使用Promise对象的then方法设置resolve函数内容 console.log(data) })
3.使用RxJs获得异步方法的数据
-
RxJs处理异步主要是通过其中的Observable对象完成的,且RxJs和Promise的基本用法类似,只是关键字不同。Promise里面用的是then()和resolve(),而RxJs里面用的是next()和subscribe()。
-
定义需要执行回调函数的方法
import {Observable} from 'rxjs'; //... getRxjsData() { return new Observable((observable)=>{ setTimeout(()=>{ var username = 'Jack'; //成功时调用next()方法执行 observable.next(username); //失败时调用error()方法执行 //observable.error('这是一个错误信息'); },1000);//设置异步方法 }) }
-
调用方法时传入成功和失败执行的方法
var rxjsData = this.getRxjsData();//返回的是Observable对象 rxjsData.subscribe((data)=>{ console.log(data);//第一个参数定义回调成功next的调用方法 });
-
Promise创建之后,动作是无法撤回的,Observable不同,动作可以通过unsubscribe()方法中途撤回,而且Observable在内部做了智能的处理。
var stream = this.getRxjsData(); var subscribedStream=streem.subscribe((data)=>{ console.log(data); }); //使用订阅返回的内容进行撤回操作,取消订阅 setTimeout(()=>{ subscribedStream.unsubscribe(); },1000);
-
Promise无法做到让异步里面的方法多次执行,最终结果要么resole(兑现)、要么 reject (拒绝),而且都只能触发一次。如果在同一个 Promise 对象上多次调用 resolve 方法, 则会抛异常。而Observable 不一样,它可以不断地触发下一个值。
-
Promise对象如果按照如下的方式使用setInterval()多次执行resolve方法会抛出异常
let promise = new Promise(resolve => { setInterval(() => { resolve('---promise setInterval---'); }, 2000); }); promise.then(value => console.log(value));
-
RxJs对象如果按照如下的方式使用setInterval()多次执行next()方法会正常执行
let stream = new Observable<number>(observer => { let count = 0; setInterval(() => { observer.next(count++); }, 1000); }); stream.subscribe(value => console.log("Observable>"+value));
-
-
RxJs使用的工具函数
-
注意:Angular6 以后使用以前的 rxjs 方法,必须安装 rxjs-compat 模块才可以使用 map、filter 方法。
npm install rxjs-compat
-
filter方法主要作用是过滤;map方法主要作用是对数据处理,将处理之后的数据返回。
-
Angular6之前使用方法
import {Observable} from 'rxjs'; import 'rxjs/Rx'; //... let stream= new Observable<any>(observer => { let count = 0; setInterval(() => { observer.next(count++); }, 1000); }); stream.filter(val=>val%2==0) .subscribe(value => console.log("filter>"+value)); stream.map(value => {return value * value}) .subscribe(value => console.log("map>"+value));
-
Angular6.X以后Rxjs6.x的变化及使用
-
RxJs变化参考文档http://bbs.itying.com/topic/5bfce189b110d80f905ae545
-
RXJS6 改变了包的结构,主要变化在 import 方式和 operator 上面以及使用 pipe()
import {Observable} from 'rxjs'; import {map,filter} from 'rxjs/operators'; //... let stream= new Observable<any>(observer => { let count = 0; setInterval(() => { observer.next(count++); }, 1000); }); stream.pipe(filter(val=>val%2==0))//表示只保留偶数 .subscribe(value => console.log("filter>"+value)); //可以使用pipe()方法,定义filter和map等方法的处理 stream.pipe(filter(val=>val%2==0), map(value => {return value * value })) .subscribe(value => console.log("map>"+value));
-
-
-
RxJs延迟执行
-
在RxJs中可以使用
fromEvent(dom,时间).pipe(()=>{处理函数})
的方式将Dom转换成dom流,对dom流进行处理,实例如下import {Observable,fromEvent} from 'rxjs'; import {map,filter,throttleTime} from 'rxjs/operators'; var button = document.querySelector('button'); fromEvent(button, 'click').pipe{ throttleTime(1000) ).subscribe(() => console.log(`Clicked`));
-
三.Angular与服务器数据交互
1.Angular发送get方法请求数据
Angular5.x 以后 get、post 和和服务器交互使用的是HttpClientModule 模块。
-
app.module.ts中引入HttpClientModule并注入(imports)
-
在使用的地方使用HttpClient在构造函数中依赖注入
constructor(public http:HttpClient){}
-
使用get方法请求数据
this.http.get('http://test.com').subscribe(response=>{ console.log(response); });
2.Angular发送post方法提交数据
-
同样引入HttpClientModule和依赖注入HttpClient对象
-
定义请求头内容并发送post请求
const httpOptions = {//定义请求头对象内容 headers: new HttpHeaders({'Content-Type':'application/json'}) } var api = 'http://test.com'; this.http.post(api,{'username':'Jack'},httpOptions).subscribe(reponse=>{ console.log(response); })
3.Angular使用Jsonp请求数据
-
当后台不允许跨域时,可以发送jsonp解决跨域问题(跨域解决方案),jsonp的原理是本地写一个方法在远程进行执行并返回给本地【使用jsonp发送请求要求服务器必须支持jsonp】
-
在app.module.ts中引入HttpClientModule/HttpClientJsonpModule并注入
-
使用的ts中构造方法注入HttpClient
-
发送jsonp请求数据
let api = 'http://test.com'; //jsonp方法的第二个参数是callback或者cd(根据服务器而定的) this.http.jsonp(api,'callback').subscribe(response=>{ console.log(response); })
4.Angular使用第三方模块axios请求数据
-
安装axios
cnpm install axios --save
-
用到的地方引入axios
import axios from 'axios';
-
使用axios
- 定义Get方法请求数据
axiosGet(api) { return new Promise((resolve,reject)=>{ axios.get(api) .then((response)=>{ //handle success resolve(response); }); }) }
- 调用get方法
let promiseObj = this.axiosGet(api); promiseObj.then((val)=>{ console.log(val) })
四.Angular中的路由
基本路由知识请查阅其他材料,本章介绍路由中易混淆内容
1.Angular routerLink跳转页面
-
html编写routerLink进行点击跳转路由
<!-- 直接编写routerLink属性值的方式 --> <a routerLink="/home">首页</a> <!-- 另一种编写方式 --> <a [routerLink]="['/home']">首页</a> <a routerLink="/news">新闻</a>
-
ts设定默认路由
{ //匹配不到路由的时候默认加载的组件或者跳转的路由 path: '**', /*任意的路由*/ // component:HomeComponent redirectTo:'home' }
2.Angular routerLinkActive设置routerLink默认选中路由
-
使用routerLinkActive可以设置当当前路由被选中时,则显示active样式(active样式需要自己编写
.active{color:red;}
)<h1> <a [routerLink]="[ '/home' ]" routerLinkActive="active">首页</a> <a [routerLink]="[ '/news' ]" routerLinkActive="active">新闻</a> </h1>
3.动态路由
路径方式传值是在ActivatedRoute对象的params属性中保存,请求参数方式传值是在ActivatedRoute对象的queryParams属性中保存,且都是Observable对象
-
配置动态路由
const routes: Routes = [ {path: 'home', component: HomeComponent}, {path: 'news', component: NewsComponent}, {path: 'newscontent/:id', component: NewscontentComponent}, { path: '', redirectTo: '/home',//使用redirectTo定义当匹配当前路由时重定向到哪个路由 pathMatch: 'full' }];
-
跳转传值
<a [routerLink]="['/newscontent/',aid]">跳转到详情</a> <a routerLink="/newscontent/{{aid}}">跳转到详情</a>
-
获取动态路由的值
import { ActivatedRoute} from '@angular/router'; constructor( private route: ActivatedRoute) {} ngOnInit() { console.log(this.route.params); this.route.params.subscribe(data=>this.id=data.id); }
-
请求参数形式传值
<!-- 使用queryParams结合routerLink实现请求参数传值,其中key是ts中定义的变量 --> <a [routerLink]="['/newscontent']" [queryParams]="{aid:key}">跳转</a>
-
获取参数形式传值的数据
import { ActivatedRoute} from '@angular/router'; constructor( private route: ActivatedRoute) {} ngOnInit() { console.log(this.route.queryParams); this.route.queryParams.subscribe(data=>this.id=data.aid); }
-
动态路由的ts跳转
-
引入Router
import { Router } from '@angular/router';
-
初始化Router对象
constructor(private router: Router) {}
-
路由跳转
this.router.navigate(['/news', hero.id]);
-
-
路由Get传值(请求参数传值)ts跳转
-
引入NavigationExtras
import { Router ,NavigationExtras} from '@angular/router';
-
定义一个 goNewsContent 方法执行跳转,用 NavigationExtras 配置传参
goNewsContent(){ let navigationExtras: NavigationExtras = { queryParams: { 'session_id': '123' }//配置queryParams }; this.router.navigate(['/news'],navigationExtras); }
-
4.父子路由【嵌套路由】
-
父子路由实战
-
配置路由
{ path: 'news', component:NewsComponent, children: [ { path:'newslist', component:NewslistComponent }, { path:'newsadd', component:NewsaddComponent } ] }
-
父组件中定义router-outlet
<router-outlet></router-outlet>
-
五.Angular模块
1.Angular内置模块
2.Angular自定义模块
- 当我们项目比较小的时候可以不用自定义模块。但是当我们项目非常庞大的时候把所有的组件都挂载到根模块里面不是特别合适。所以这个时候我们就可以自定义模块来组织我们的项目。并且通过 Angular 自定义模块可以实现路由的懒加载。
- 使用
cli
生成module:ng g m testmodule
,创建带路由的module:ng g m testmodule --routing
- 注意:如果想让其他module访问创建的module中的component,需要在创建的module中exports对应的component,且在其他模块中imports当前创建的module
3.模块懒加载
-
通过配置懒加载路由的方式实现模块的懒加载
-
使用loadChildren声明懒加载路由模块,
#
前是module模块路径,#
后是module名 -
实例代码
const routes: Route = [ { path:'user', loadChildren:'./module/user/user.module#UserModule' } ]
-