Web

Angular学习笔记

Posted by Kerwen Blog on October 13, 2021

命令行汇总

1
2
3
4
5
6
7
    npm install -g @angular/cli  
    ng version  

    ng new projectName   // create new angular project  
    ng serve --open      // run project  
    ng g component <component-name>    // create new component
    ng g service <service-name>     // create new service

使用指定版本的Angular

1
2
3
    npm uninstall -g @angular/cli
    npm install -g @angular/cli@13.2.0
    ng new my-app-name

将第三方module升到最新

1
2
3
    npm install -g npm-check-updates
    ncu --upgrade
    npm install

基本概念

组件

组件是构成应用的砖块。组件包括三个部分:

1
2
3
    带有 @Component() 装饰器的 TypeScript 类  
    HTML 模板  
    样式文件  

@Component() 装饰器会指定如下 Angular 专属信息:

1
2
3
    一个 CSS 选择器,用于定义如何在模板中使用组件。  
    一个 HTML 模板,用于指示 Angular 如何渲染此组件。   
    一组可选的 CSS 样式,用于定义模板中 HTML 元素的外观。  

每个组件都必须声明在(且只能声明在)一个 NgModule 中。

模板

每个组件都有一个 HTML 模板,用于声明该组件的渲染方式。你可以内联它或用文件路径定义此模板。
Angular 使用额外的语法扩展了 HTML,使你可以从组件中插入动态值。当组件的状态更改时,Angular 会自动更新已渲染的 DOM。

1
    <p> { { message } }</p>  

双花括号 —— 它们指示 Angular 对其中的内容进行插值。

1
    <p [id]="sayHelloId" [style.color]="fontColor">You can set my color in the component!</p>  

方括号 —— 属性绑定,在将 Property 或 Attribute 绑定到组件类中的值。

1
    <button (click)="sayMessage()" [disabled]="canClick">Trigger alert message</button>

圆括号 —— 事件监听

安装

  1. Install NodeJs
  2. Start a cmd and install following command:

    1
    
     npm install -g @angular/cli
    
  3. Input following command to check Angular version

    1
    
     ng version
    
  4. VSCode 安装插件

    1
    
     Angular Snippet
    

基础

创建一个项目

Initialize a new project:

1
    ng new projectName

可以使用ng new projectName --skip-install跳过依赖安装,然后使用npm install安装依赖项

运行应用

1
    ng serve --open

目录结构

angular.json 里面记录了网页的入口 index, main
package.json 里面记录了所有的script命令
src/index.html 网站首页
src/main.ts 加载哪个module
src/app/app.module.ts app module里面加载了哪个component
src/app/app.component.ts Angular根组件,里面包括 修饰器, template,style和Appcomponent的一些属性设定。

image

根模块app.module.ts: image

安装其他module

1
2
    npm install jquery@3.1.1 --save
    npm install bootstrap@3.3.7 --save

安装完成之后,package.json会发生变化,记录已经安装的module。
在angular.json中新安装的module:

1
2
3
4
    "scripts": [
          "../node_modules/jquery/dist/jquery.js",
          "../node_modules/bootstrap/dist/js/bootstrap.js"
        ]

安装module对应的types:

1
2
3
    npm install @types/jquery@2.0.39 --save-dev
    
    npm install @types/bootstrap@3.3.32 --save-dev

创建新组件

1
    ng g component News

每添加一个组件,会生成对应的文件夹和文件,并且自动在app.modules.ts里面注册该组件:

1
2
3
4
5
6
7
    import { NewsComponent } from './News/news.component';

    @NgModule({
    declarations: [
        AppComponent,
        NewsComponent
    ],

每个组件包括三部分html, css, tsimage

ts文件:

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

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

            constructor() { }

            ngOnInit(): void {
            }
    }

创建新的service

1
    ng g service services/storage

一个新创建好的空服务

1
2
3
4
5
6
7
8
9
10
11
    import { Injectable } from '@angular/core';

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

        constructor() { }

        // Add new function here
    }

需要在app.modules.ts里面引入新添加的服务

1
2
3
    import {StorageService} from './services/storage.service';
    ...
    providers: [StorageService],

在component中调用该service:

1
2
3
4
5
    import {StorageService} from './services/storage.service';

    constructor(public storage:StorageService) {
      this.storage.function();
    }

基本数据结构

  1. 数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     public arr:any[]=['111','222','333'];
        
     public userlist:any[]=[{
             username:'Zhang',
             age:20
     },{
             username:'Li',
             agent:21
     }]
    

TypeScript 学习

绑定

  1. 绑定数据

    component.ts:

    1
    
     title:string ='data';   //声明一个属性
    

    compoonent.html:

    1
    
     <h1> { {title} } </h1> 
    

    双花括号语法是 Angular 的插值绑定语法。 这个插值绑定的意思是把组件的 title 属性的值绑定到 HTML 中的 h1 标记中。

  2. 绑定属性

    component.html:

    1
    
     <div [title]="student"></div>
    

    component.ts

    1
    
     student:string='abc';
    
  3. 绑定HTML:

    component.html:

    1
    
     <span [innerHTML]="content"></span>
    

    component.ts:

    1
    
     content="<h2>这是一个html标签</h2>"
    
  4. 绑定数组

    component.html:

    1
    2
    3
    
     <li *ngFor="let item of list">
             { {item} }
     </li>
    

    component.ts:

    1
    
     list:string[] = ['111','222','333']
    
  5. 绑定事件:
    html:

    1
    
     <button (click)="fun()">执行事件</button>
    

    ts:

    1
    2
    3
    
     fun(){
             console.log("test");
     }
    

    input事件绑定:

    1
    
     <input type="text" (keydown)="keyDown($event)"/>
    

    ts:

    1
    2
    3
    
     keyDown(event){
             console.log(event.target.value);
     }
    
  6. 双向数据绑定 MVVM 只是针对表单

    双向数据绑定必须引入FormModule
    app.module.ts中:

    1
    2
    3
    4
    5
    
     import {FormsModule} from '@angular/forms'
    
     import:[
          FormsModule,   
     ],
    

    html:

    1
    
     <input type="text" [(ngModel)]="keywords"/>
    

    ts:

    1
    
     keywords:string="default value"
    

数据用双括号{ { } },属性用[]绑定,事件用()绑定,双向绑定用[()]

指令语句

  1. ngFor

    1
    2
    3
    4
    5
    6
    7
    
     <li *ngFor="let item of list">
             { {item} }
     </li>
    
     <li *ngFor="let item of list;let key=index;">
             { {key} }----{ {item} }
     </li>
    
  2. ngIf

    1
    2
    3
    
     <div *ngIf="flag">
            
     </div>
    
  3. ngSwitch

    1
    2
    3
    4
    5
    6
    7
    8
    
     public orderStatus:number=1
    
     <ul [ngSwitch]="orderStatus">
             <li *ngSwitchCase="1">已支付</li>
             <li *ngSwitchCase="2">订单已经确认</li>
             <li *ngSwitchCase="3">已发货</li>
             <li *ngSwitchDefault>无效</li>
     </ul>
    
  4. ngClass

    1
    
     <div [ngClass]="{'red': flag}">ngClass演示</div>
    

    第一条显示红色:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
     css:
     .red {
             color:red;
     }
     .orange{
             color:orange;
     }
    
     html:
     <ul>
         <li *ngFor="let item of list; let key=index;" [ngClass]="{'red': key==0, 'orange':key==1}">
             { {key} } -- { {item} }
         </li>
     </ul>
    
  5. ngStyle

    1
    
     <p [ngStyle]="{'color': 'red'}">ngStyle</p>
    

管道

管道用来格式化数据, 处理原始值到显示值的转换

1
2
3
4
5
    public birthday:any=new Date();

    <p>我的生日是{ {birthday | date:'yyyy-MM-dd HH:mm:ss'} }</p>

    <p>圆周率是{ {pi | number:'2.2-2'} }</p>

自定义管道

1
    ng g pipe pipe/multiple 

遇到以下问题:

1
    No provider for ControlContainer ("[ERROR ->]<form name="searchForms" role="forms">  

解决方法:
在使用管道的时候,需要引入 ReactiveFormsModule,同时还要引入 FormsModule

1
2
3
4
5
6
    imports: [
      BrowserModule,
      AppRoutingModule,
      ReactiveFormsModule,  
      FormsModule,  
    ],

表单

采用双向绑定的方式:
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
<div class="people_list">
    <ul>
        <li>姓名: <input type="text" [(ngModel)]="peopleInfo.username" class="username"></li>
        <li>性别:
            <input type="radio" value="1" name="sex" id="sex1" [(ngModel)]="peopleInfo.sex">
            <label for="sex1">男</label> &nbsp;&nbsp;&nbsp;  
            <input type="radio" value="2" name="sex" id="sex2" [(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"></option>
            </select>
        </li>
        <li>爱好:
            <span *ngFor="let item of peopleInfo.hobbyList; let key=index;">
                <input type="checkbox" [id]="'check'+key" [(ngModel)]="item.checked" > 
                <label [for]="'check'+key"></label>&nbsp;&nbsp; 
            </span>
        </li>
        <li>备注:
            <textarea name="mark" id="mark" cols="30" rows="10" [(ngModel)]="peopleInfo.mark"></textarea>
        </li>
    </ul>
    <button (click)="doSubmit()" class="submit">获取表单的内容</button>
</div>

css:

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
    *{
            margin:0px;
            padding:0px;
    }
    ul,ol{
            list-style-type:none;
    }
    h2{
            text-align:center;
    }
    .people_list{
            width: 400px;
            margin:40px auto;
            padding: 20px;
            border: 1px sold #eee;

            li{
                    height:50px;
                    line-height:50px;
                    input{
                            width:300px;
                            height:32px;
                    }
            }
    }

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
export class FormComponent implements OnInit {

    cityList:string[] = ['北京','上海','深圳'];
            
    public peopleInfo:any={
        username:'',
        sex:'1',
        city:'北京',
        hobbyList: [{
            title:'吃饭',
            checked:false
        },{
            title:'睡觉',
            checked:false
        },{
            title:'玩游戏',
            checked:true
        }],
        mark:''
    }
    constructor() { }

    ngOnInit(): void {
    }

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

LocalStorage

HTML5 提供了两种在客户端存储数据的新方法:

localStorage - 没有时间限制的数据存储
sessionStorage - 针对一个 session 的数据存储

localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。

1
2
3
4
5
6
7
8
9
10
11
    set(key,value){
      localStorage.setItem(key, JSON.stringify(value));
    }

    get(key){
      return JSON.parse(localStorage.getItem(key));
    }

    remove(key){
      localStorage.removeItem(key);
    }

查看方法
进入开发者工具
选择 Application
在左侧 Storage 下 查看 Local Storage 和 Session Storage

image

操纵DOM元素

  1. 原生js操作
    html:

    1
    2
    3
    
     <div id="box1">
             我是一个dom节点
     </div>
    

    ts:
    建议把dom操作放在视图加载完成`ngAfterViewInit`以后触发

    1
    2
    3
    4
    5
    
     ngAfterViewInit():void{
         let obox:any=document.getElementById('box1');
         console.log(obox.innerHTML);
         obox.style.color="blue"
     }
    
  2. ViewChild
    ViewChild对原生DOM进行了封装.
    html:

    1
    2
    3
    
     <div #myBox>
             我是一个dom节点
     </div>
    

    ts:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     // 引入ViewChild
     import {component,onInit, ViewChild} from '@angular/core';
    
     @ViewChild('myBox') myBox:any;
    
     ngAfterViewInit():void{
             this.myBox.nativeElement.style.width='100px';
             this.myBox.nativeElement.style.height='100px';
     }
    

    ViewChild允许在父组件中调用子组件的方法
    news.component.html:

    1
    
     <app-header #header></app-header>
    

    news.component.ts:

    1
    2
    3
    4
    5
    
     @ViewChild('header') header:any;
    
     ngAfterViewInit():void{
             this.header.childFun();
     } 
    

组件之间通讯

父 -> 子 @Input装饰器

父组件不仅可以给子组件传递简单的数据, 还可以把自己的方法以及整个父组件传递给子组件。
父组件:
ts:

1
2
3
4
5
6
    public title:string="首页组件的标题";

    run()
    {
            console.log("这是父组件的方法");
    }

html:

1
    <app-header [title]="title" [run]='run'></app-header>

子组件app-header:

ts:

1
2
3
4
5
6
7
8
9
    import {Input} from '@angular/core'

    @Input() title:any;     //接受父组件传来的数据 
    @Input() run:any;

    getParentRun()
    {
            run();          //执行父组件的run方法
    }

html:

1
2
3
    <header></header>

    <button (click)="getParentRun()">子组件执行父组件的方法</button>

子 -> 父

方法1:使用ViewChild获取DOM
子组件:
ts:

1
2
3
4
    public msg="我是子组件的一个msg";
    run(){
            alert("我是子组件的run方法");
    }

父组件:
html:

1
2
3
4
    <app-footer #footer></app-footer>

    <button (click)="getChildMsg()>获取字组件数据</button>
    <button (click)="getChildRun()">执行子组件的方法</button>

ts:

1
2
3
4
5
6
7
8
9
10
    import {ViewChild} from '@angular/core';

    @ViewChild('footer') footer:any;
 
    getChildMsg(){
            alert(this.footer.msg)
    }
    getChildRun(){
            this.footer.run()
    }

方法2: @Output + 事件驱动 EventEmitter
子组件:
ts:

1
2
3
4
5
6
7
    import {Output,EventEmitter} from '@angular/core';

    @Output() private outer=new EventEmitter<string>();
    
    sendParent(){
            this.outer.emit("msg from child");
    }

html:

1
    <button (click)=sentParent()>通过子组件向父组件广播</button>

父组件:

html:

1
    <app-header (outer)="run($event)"></app-header>

ts:

1
2
3
4
    run(e)
    {
            console.log(e);
    }

非父子附件之间通信

  1. 通过服务来实现非父子组件之间的通信
  2. 通过LocalStorage

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 销毁指令或组件之前立即调用。

获取异步数据

回调函数

request.service.ts:

1
2
3
4
5
6
    getCallbackData(cb){
            setTimeout(()=>{
                    var data='张三';
                    cb(data);
            },1000)
    }

HomeComponent.ts:

1
2
3
4
5
6
7
8
9
    import {RequestService} from '../../services/request.servcie'

    constructor(public request:RequestService){}

    ngOnInit(){
            let callback = this.request.getCallbackData((data)=>{
                    console.log(data);
            });
    }

Promise

request.service.ts:

1
2
3
4
5
6
7
8
    getPromiseData(){
       return new Promise((resolve,reject)=>{
         setTimeout(()=>{
           var data='张三';
             resolve(data);
          },1000)
        })
    }

HomeComponent.ts:

1
2
3
4
5
6
7
8
9
10
    import {RequestService} from '../../services/request.servcie'

    constructor(public request:RequestService){}

    ngOnInit(){
      var prmiseData=this.request.getPromiseData();
      promiseData.then((data)=>{
            console.log(data);
      })
    }

Rxjs

request.service.ts:

1
2
3
4
5
6
7
8
9
10
11
    import{Observable} from 'rxjs'

    getRxjsData(){
            return new Observable((observer)=>{
                    setTimeout(()=>{
                      var data='张三';
                      observer.next(data);
                      //observer.error("error message");
                    },1000)
            })
    }

HomeComponent.ts:

1
2
3
4
5
6
7
8
9
10
    import {RequestService} from '../../services/request.servcie'

    constructor(public request:RequestService){}

    ngOnInit(){
            var rxjsData = this.request.getRxjsData();
            rxjsData.subscribe((data)=>{
                    console.log(data);
            })
    }

相比Promise方法, Rxjs可以取消订阅操作unsubscribe, 多次执行, 有map, filter工具,可以对数据进行处理.
filter筛选数据,map处理数据:

request.service.ts:

1
2
3
4
5
6
7
8
9
10
11
    import{Observable} from 'rxjs'

    getRxjsIntervalNum(){
            let count=0;
            return new Observable((observer)=>{
                    setInterval(()=>{
                      count++;
                      observer.next(count)
                    },1000)
            })
    }

HomeComponent.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    import {RequestService} from '../../services/request.servcie'
    import {map, filter} from 'rxjs/operators'

    var streamNum=this.request.getRxjsIntervalNum();
    streamNum.pipe(
            filter((value)=>{
                    if(value%2==0){
                            return true;    //筛选偶数
                    }
            })
            map((value)=>{
                    return value * value;   //处理数据
            })
    )
    .subscribe((data)=>{
            console.log(data);
    })



    streamNum.pipe(
            
    )

数据交互 get post

get

需要在app.module.ts中引入httpClientModule

1
2
3
4
5
    import {HttpClientModule} from '@angular/common/http';

    imports:[
            HttpClientModule
    ]

在需要使用的地方:

1
2
3
4
5
6
7
8
9
10
    import {HttpClientModule} from '@angular/common/http';

    constructor(public http:HttpClient){}
     
    get(){
            var api="test.com/api/productlist";
            this.http.get(api).subscribe(response:any => {
                    console.log(response);
            });
    }

get请求底层封装了Rxjs

post

1
2
3
4
5
6
7
8
    const httpOptions={
            headers:new httpHeaders({'Content-Type':'application/json'})
    }

    var api="test.com/api/doLogin";
    this.http.post(api,{username:'张三',age:'20'}, httpOptions).subscribe(response =>{
            console.log(response);
    });

Jsonp

Jsonp是跨域的一种解决方案, 前提是服务器支持jsonp请求

需要在app.module.ts中引入httpClientModule

1
2
3
4
5
6
    import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http';

    imports:[
            HttpClientModule,
            HttpClientJsonpModule
    ]

在需要使用的地方:

1
2
3
4
5
6
7
8
9
10
    import {HttpClientModule} from '@angular/common/http';

    constructor(public http:HttpClient){}

    getJsonpData(){
            let api="test.com/api/productlist";
            this.http.jsonp(api, 'callback').subscribe((response)=>{
                    console.log(response);
            })
    }

使用第三方模块axios请求数据

1
    npm install axios --save

路由

路由就是根据不同的url地址,动态的让根组件加载其他组件来实现一个单页面应用。

src\app\app-routing.module.ts中引入并配置路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    import {HomeComponent} from './home/home.component';
    ...


    const routes:Routes =[
            {path: 'home', component:HomeComponent},
            {path: 'news', component:NewsComponent},
            {path: 'newscontent/:id', component:NewscontentComponent},
            {
                    path:'',
                    redirectTo:'/home',
                    pathMath: 'full'
            }
    ]

在html中<router-outlet>用于动态加载组件

1
2
3
4
5
    <h1>
            <a routerLink="/home">首页</a>
            <a routerLink="/news">新闻</a>
    </h1>
    <router-outlet></router-outlet>

默认路由:

1
2
3
4
5
6
    const routes:Routes =[
            ...
            {
                    path:'**', redirectTo:'home'
            }
    ]

当前选中页面高亮:

HTML:

1
2
3
4
5
    <h1>
            <a routerLink="/home" routerLinkActive="active">首页</a>
            <a routerLink="/news" routerLinkActive="active">新闻</a>
    </h1>
    <router-outlet></router-outlet>

css:

1
2
3
    .active{
            color:red;
    }

路由传值

get传值

使用queryParams进行传值
html:

1
2
3
4
5
    <ul>
            <li *ngFor="let item of list; let key=index;">
                    <a [routerLink]="['/newscontent']" [queryParams]="{aid:key,name:'张三'}">跳转到新闻详情</a>
            </li>
    </ul>

在子组件ts中接收参数:

1
2
3
4
5
6
7
8
9
    import {ActiveRoute} from '@angular/router';

    constructor(public route:ActiveRoute){}

    ngOnInit(){
           this.route.queryParams.subscribe((data)=>{
                   console.log(data);
           })
    }

动态路由

修改路由配置

1
2
3
    const routes:Routes =[
            {path: 'newscontent/:aid', component:NewscontentComponent},
    ]

html:

1
2
3
4
5
    <ul>
            <li *ngFor="let item of list;let key=index>
                    <a [routerLink]="['/newscontent', key]">跳转到新闻详情</a>
            </li>
    </ul>

在子组件ts中接收参数:

1
2
3
4
5
6
7
8
9
    import {ActiveRoute} from '@angular/router';

    constructor(public route:ActiveRoute){}

    ngOnInit(){
           this.route.params.subscribe((data)=>{
                   console.log(data);
           })
    }

动态路由js跳转

html:

1
    <button (click)="goNewsContent()">js跳转路由</button>

ts:

1
2
3
4
5
6
7
8
9
10
11
    import {Router} from '@angular/router'

    constructor(public route:Router){}

    goNewsContent(){
            this.router.navigate(['/newscontent','1234']);
    }

    goHome(){
            this.router.navigate(['/home']);
    }

js跳转路由并且get传值

需要引入NavigationExtras模块

1
2
3
4
5
6
7
8
9
10
    import {Router,NavigatioinExtras} from '@angular/router';

    goNewConent(){
            let navigationExtras:NavigationExtras ={
                    queryParams:{'session_id':'123'},
                    fragment:'anchor'
            }

            this.router.navigate(['/news'], navigationExtras);
    }

嵌套路由

使用children修改路由配置

1
2
3
4
5
6
7
8
9
10
    const routes:Routes =[
            {
                    path: 'home', component:HomeComponent,
                    children:[
                            {path:'welcome', component:WelcomeComponent},
                            {path:'setting', component:SettingComponent},
                            {path: '**', redirectTo:'welcome'},
                    ]
            },
    ]

html:

1
2
3
    <a [routerLink]="['/home/welcome']">欢迎首页</a>

    <router-outlet></router-outlet>

辅助路由

1
2
3
4
5
    <a [routerLink]="[{outlets:{aux:'chat'}}]">开始聊天</a>
    <a [routerLink]="[{outlets:{aux:null}}]">结束聊天</a>
    <router-outlet name="aux"></router-outlet>

    {path:'chat', component:ChatComponent, outlet: 'aux'}        

路由守卫

  1. CanActivate:处理导航到某路由的情况。

    1
    2
    3
    4
    5
    
     export class LoginGuard implements CanActivate{
             CanActivate(){
                     return true;
             }
     }
    

    配置路由:

    1
    2
    3
    4
    5
    6
    7
    
     const routes:Routes =[
             {path:'product/:id', component:ProductComponent, canActivate:[LoginGuard]},
     ]
    
     @NgModule({
             providers: [LoginGuard]
     })
    
  2. CanDeactivate:处理从当前路由离开的情况.

    1
    2
    3
    4
    5
    
     export class UnsavedGuard implement CanDeactivate<ProductComponent>{
             canDeactivate(component:ProductComponent){
                     return window.confirm("你还没有保存,确定要离开吗?");
             }
     }
    

    配置路由:

    1
    2
    3
    4
    5
    6
    7
    
     const routes:Routes =[
             {path:'product/:id', component:ProductComponent, canDeactivate:[UnsavedGuard]},
     ]
    
     @NgModule({
             providers: [UnsavedGuard]
     })
    
  3. Resolve:在路由激活之前获取路由数据

自定义模块

1
    ng g module module/user

在自定义模块中创建新的component

1
    ng g component module/user/components/order

在自定义模块的module.ts中指定要export的组件 user.module.ts

1
    exports:[UserComponent],

引入自定义模块:

1
2
3
4
5
    import {UserModule} from './module/user/user.module';

    imports:[
            UserModule,
    ],

自定义模块的懒加载

创建模块时自动创建路由

1
    ng g module module/user --routing

创建模块的根组件

1
    ng g component module/user

配置自定义模块的路由
user-routing.module.ts

1
2
3
4
5
    const routes:Routes =[
            {
                    path:'', component:UserComponent
            }
    ]

修改根路由配置
app-routing.module.ts

1
2
3
4
5
    const routes:Routes=[
            {
                    path:'user', loadChildren:'./module/user/user.module#UserModule'
            }
    ]

响应式编程

Other

定时器

1
2
3
4
5
6
7
8
9
    // 只执行一次
    setTimeout(()=>{
            console.log("write log after 1 second");
    },1000)

    // 执行多次
    SetInterval(()=>{
            console.log("write log every 1 second");
    }, 1000)

reference

localStorage、sessionStorage、Cookie的区别及用法

问题

  1. .debounceTime
    需要 import ‘rxjs/Rx’ //搜索
    npm install –save rxjs-compat