久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      深入了解Angular(新手入門(mén)指南)

      本篇文章帶大家深入了解Angular,分享最全的Angular新手入門(mén)指南,希望對(duì)大家有所幫助!

      深入了解Angular(新手入門(mén)指南)

      前端(vue)入門(mén)到精通課程,老師在線輔導(dǎo):聯(lián)系老師
      Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調(diào)試工具:點(diǎn)擊使用

      Angular概述

      Angular 是谷歌開(kāi)發(fā)的一款開(kāi)源的 web 前端框架,基于 TypeScript ?!鞠嚓P(guān)教程推薦:《angular教程》】

      和 react 與 vue 相比, Angular 更適合中大型企業(yè)級(jí)項(xiàng)目。

      Angular程序架構(gòu)

      深入了解Angular(新手入門(mén)指南)

      Angular優(yōu)勢(shì)

      • 可伸縮性:基于RxJS 、immutable.js和其他推送模型,能適應(yīng)海量數(shù)據(jù)需求
      • 跨平臺(tái):漸進(jìn)式應(yīng)用(高性能、離線使用、免安裝),原生(Ionic),桌面端
      • 生產(chǎn)率:模版(通過(guò)簡(jiǎn)單而強(qiáng)大的模版語(yǔ)法,快速創(chuàng)建UI視圖),CLI(快速進(jìn)入構(gòu)建環(huán)節(jié)、添加組件和測(cè)試,然后立即部署)
      • 測(cè)試:?jiǎn)卧獪y(cè)試(支持Karma、Jasmine等工具進(jìn)行單元測(cè)試),端到端測(cè)試(支持Protractor等工具進(jìn)行端到端測(cè)試)

      @angular/cli腳手架

      ng new 新建項(xiàng)目

      • ——routing 配置路由
      • ——style=css|scss|less 配置css樣式

      ng serve 啟動(dòng)項(xiàng)目

      • ——port 4200 端口號(hào),默認(rèn)4200
      • ——open 自動(dòng)打開(kāi)瀏覽器

      ng build 打包項(xiàng)目

      • ——aot 預(yù)編譯
      • ——prod 壓縮打包
      • ——base-href=/static/

      ng generate 創(chuàng)建模塊/組件/服務(wù)

      • module ——routing 創(chuàng)建模塊
      • component 創(chuàng)建組件
      • service / 創(chuàng)建服務(wù)

      文件加載順序

      main.ts => app.module.ts => app.component.ts => index.html => app.component.html

      項(xiàng)目目錄結(jié)構(gòu)

      |-- project 	|-- .editorconfig // 用于在不同編輯器中統(tǒng)一代碼風(fēng)格 	|-- .gitignore // git中的忽略文件列表 	|-- README.md // markdown格式的說(shuō)明文件 	|-- angular.json // angular的配置文件 	|-- browserslist // 用于配置瀏覽器兼容性的文件 	|-- karma.conf.js // 自動(dòng)化測(cè)試框架Karma的配置文件 	|-- package-lock.json // 依賴(lài)包版本鎖定文件 	|-- package.json // npm的包定義文件 	|-- tsconfig.app.json // 用于app項(xiàng)目的ts配置文件 	|-- tsconfig.json // 整個(gè)工作區(qū)的ts配置文件 	|-- tsconfig.spec.json // 用于測(cè)試的ts配置文件 	|-- tslint.json // ts的代碼靜態(tài)掃描配置 	|-- e2e // 自動(dòng)化集成測(cè)試目錄 	|-- src // 源代碼目錄   |-- src // 源代碼目錄 	|-- favicon.ico // 收藏圖標(biāo) 	|-- index.html // 單頁(yè)應(yīng)用到宿主HTML 	|-- main.ts // 入口 ts 文件 	|-- polyfills.ts // 用于不同瀏覽器的兼容腳本加載 	|-- styles.css // 整個(gè)項(xiàng)目的全局css 	|-- test.ts // 測(cè)試入口 	|-- app // 工程源碼目錄 	|-- assets // 資源目錄 	|-- environments // 環(huán)境配置 		|-- environments.prod.ts // 生產(chǎn)環(huán)境 		|-- environments.ts // 開(kāi)發(fā)環(huán)境
      登錄后復(fù)制

      Angular模塊

      在 app.module.ts 中定義 AppModule,這個(gè)根模塊會(huì)告訴 Angular 如何組裝應(yīng)用。

      深入了解Angular(新手入門(mén)指南)

      @NgModule 裝飾器

      @NgModule 接受一個(gè)元數(shù)據(jù)對(duì)象,告訴 Angular 如何編譯和啟動(dòng)應(yīng)用

      設(shè)計(jì)意圖

      • 靜態(tài)的元數(shù)據(jù)(declarations)
      • 運(yùn)行時(shí)的元數(shù)據(jù)(providers)
      • 組合與分組(imports 和 exports)

      元數(shù)據(jù)

      • declarations 數(shù)組:模塊擁有的組件、指令或管道,注意每個(gè)組件/指令/管道只能在一個(gè)模塊中聲明
      • providers 數(shù)組: 模塊中需要使用的服務(wù)
      • imports 數(shù)組:導(dǎo)入本模塊需要的依賴(lài)模塊,注意是模塊
      • exports 數(shù)組: 暴露給其他模塊使用的組件、指令或管道等
      • bootstrap 數(shù)組:指定應(yīng)用的主視圖(稱(chēng)為根組件)通過(guò)引導(dǎo)根 AppModule 來(lái)啟動(dòng)應(yīng)用,即項(xiàng)目剛加載時(shí)選擇讀哪個(gè)組件
      • entryComponents 數(shù)組:一般用于動(dòng)態(tài)組件

      內(nèi)置模塊

      常用的有:核心模塊、通用模塊、表單模塊、網(wǎng)絡(luò)模塊等

      深入了解Angular(新手入門(mén)指南)

      自定義模塊

      當(dāng)項(xiàng)目比較小的時(shí)候可以不用自定義模塊

      但是當(dāng)項(xiàng)目非常龐大的時(shí)候,把所有的組件都掛載到根模塊里面就不太合適了

      所以可以使用自定義模塊來(lái)組織項(xiàng)目,并且通過(guò)自定義模塊可以實(shí)現(xiàn)路由的懶加載

      模塊的tips

      導(dǎo)入其他模塊時(shí),需要知道使用該模塊的目的

      • 如果是組件,那么需要在每一個(gè)需要的模塊中都進(jìn)行導(dǎo)入
      • 如果是服務(wù),那么一般來(lái)說(shuō)在根模塊導(dǎo)入一次即可

      需要在每個(gè)需要的模塊中進(jìn)行導(dǎo)入的

      • CommonModule : 提供綁定、*ngIf 和 *ngFor 等基礎(chǔ)指令,基本上每個(gè)模塊都需要導(dǎo)入它
      • FormsModule / ReactiveFormsModule : 表單模塊需要在每個(gè)需要的模塊導(dǎo)入
      • 提供組件、指令或管道的模塊

      只在根模塊導(dǎo)入一次的

      • HttpClientModule / BrowerAnimationsModule NoopAnimationsModule
      • 只提供服務(wù)的模塊

      Angular組件

      深入了解Angular(新手入門(mén)指南)

      • 組件是 Angular 的核心,是 Angular 應(yīng)用中最基本的 UI 構(gòu)造塊,控制屏幕上被稱(chēng)為視圖的一小片區(qū)域
      • 組件必須從屬于某個(gè) NgModule 才能被其他組件或應(yīng)用使用
      • 組件在 @NgModule 元數(shù)據(jù)的 declarations 字段中引用

      @Component 元數(shù)據(jù)

      • selector :選擇器,選擇相匹配的HTML里的指令模版
      • templateUrl :將選擇器中匹配的指令同級(jí)替換成值的模版
      • template :內(nèi)嵌模版,直接可以在里面寫(xiě)HTML模版
      • styleUrls :對(duì)應(yīng)模版的樣式,為一個(gè)數(shù)組,可以引入多個(gè)css樣式控制組件
      • encapsulation:組件樣式封裝策略

      @Component({   selector: 'app-xxx',   templateUrl: 'XXX',   styleUrls: ['XXX'],   encapsulation:ViewEncapsulation.Emulated  // 不寫(xiě)則默認(rèn)該值,表示該組件樣式只作用于組件本身,不影響全局樣式,在 head 中生成單獨(dú)的 style 標(biāo)簽 })
      登錄后復(fù)制

      數(shù)據(jù)綁定

      • 數(shù)據(jù)綁定 {{data}}

      • 屬性綁定 [id]="id",其中[class.樣式類(lèi)名]=“判斷表達(dá)式”是在應(yīng)用單個(gè)class樣式時(shí)的常用技巧

      • 事件綁定 (keyup)="keyUpFn($event)"

      • 樣式綁定可以用 :host 這樣一個(gè)偽類(lèi)選擇器,綁定的樣式作用于組件本身

      • 雙向數(shù)據(jù)綁定 [(ngModel)]

        // 注意引入:FormsModule import { FormsModule } from '@angular/forms';  <input type="text" [(ngModel)]="inputValue"/> {{inputValue}}  // 其實(shí)是一個(gè)語(yǔ)法糖 [ngModel]="username" (ngModelChange)="username = $event"
        登錄后復(fù)制

      臟值檢測(cè)

      臟值檢測(cè):當(dāng)數(shù)據(jù)改變時(shí)更新視圖(DOM)

      如何進(jìn)行檢測(cè):檢測(cè)兩個(gè)狀態(tài)值(當(dāng)前狀態(tài)和新?tīng)顟B(tài))

      何時(shí)觸發(fā)臟值檢測(cè):瀏覽器事件(click、mouseover、keyup等)、setTimeout()setInterval()、HTTP請(qǐng)求

      Angular 有兩種變更檢測(cè)策略:DefaultOnPush

      可以通過(guò)在@Component元數(shù)據(jù)中設(shè)置changeDetection: ChangeDetectionStrategy.OnPush進(jìn)行切換

      Default

      優(yōu)點(diǎn):每一次有異步事件發(fā)生,Angular 都會(huì)觸發(fā)變更檢測(cè),從根組件開(kāi)始遍歷其子組件,對(duì)每一個(gè)組件都進(jìn)行變更檢測(cè),對(duì)dom進(jìn)行更新。

      缺點(diǎn):有很多組件狀態(tài)沒(méi)有發(fā)生變化,無(wú)需進(jìn)行變更檢測(cè)。如果應(yīng)用程序中組件越多,性能問(wèn)題會(huì)越來(lái)越明顯。

      OnPush

      優(yōu)點(diǎn):組件的變更檢測(cè)完全依賴(lài)于組件的輸入(@Input),只要輸入值不變就不會(huì)觸發(fā)變更檢測(cè),也不會(huì)對(duì)其子組件進(jìn)行變更檢測(cè),在組件很多的時(shí)候會(huì)有明顯的性能提升。

      缺點(diǎn):必須保證輸入(@Input)是不可變的(可以用Immutable.js解決),每一次輸入變化都必須是新的引用。

      父子組件通訊

      深入了解Angular(新手入門(mén)指南)

      父組件給子組件傳值 @input

      父組件不僅可以給子組件傳遞簡(jiǎn)單的數(shù)據(jù),還可把自己的方法以及整個(gè)父組件傳給子組件。

      // 父組件調(diào)用子組件的時(shí)候傳入數(shù)據(jù) <app-header [msg]="msg"></app-header>  // 子組件引入 Input 模塊 import { Component, OnInit ,Input } from '@angular/core';  // 子組件中 @Input 裝飾器接收父組件傳過(guò)來(lái)的數(shù)據(jù) export class HeaderComponent implements OnInit {   @Input() msg:string 	constructor() { } 	ngOnInit() { } }  // 子組件中使用父組件的數(shù)據(jù) <h2>這是頭部組件--{{msg}}</h2>
      登錄后復(fù)制

      **子組件觸發(fā)父組件的方法 @Output **

      // 子組件引入 Output 和 EventEmitter import { Component,OnInit,Input,Output,EventEmitter} from '@angular/core';  // 子組件中實(shí)例化 EventEmitter // 用 EventEmitter 和 @Output 裝飾器配合使用 <string> 指定類(lèi)型變量 @Output() private outer=new EventEmitter<string>();  // 子組件通過(guò) EventEmitter 對(duì)象 outer 實(shí)例廣播數(shù)據(jù) sendParent(){   this.outer.emit('msg from child') }  // 父組件調(diào)用子組件的時(shí)候,定義接收事件,outer 就是子組件的 EventEmitter 對(duì)象 outer <app-header (outer)="runParent($event)"></app-header>  // 父組件接收到數(shù)據(jù)會(huì)調(diào)用自己的 runParent, 這個(gè)時(shí)候就能拿到子組件的數(shù)據(jù) // 接收子組件傳遞過(guò)來(lái)的數(shù)據(jù)   runParent(msg:string){    alert(msg); }
      登錄后復(fù)制

      父組件通過(guò) ViewChild 主動(dòng)調(diào)用子組件DOM和方法

      // 給子組件定義一個(gè)名稱(chēng) <app-footer #footerChild></app-footer>  // 引入 ViewChild import { Component, OnInit ,ViewChild} from '@angular/core';  // ViewChild 和子組件關(guān)聯(lián)起來(lái) @ViewChild('footerChild') footer;  // 調(diào)用子組件 run(){    this.footer.footerRun(); }
      登錄后復(fù)制

      投影組件

      深入了解Angular(新手入門(mén)指南)

      由于組件過(guò)度嵌套會(huì)導(dǎo)致數(shù)據(jù)冗余和事件傳遞,因此引入投影組件的概念

      投影組件 ng-content 作為一個(gè)容器組件使用

      主要用于組件動(dòng)態(tài)內(nèi)容的渲染,而這些內(nèi)容沒(méi)有復(fù)雜的業(yè)務(wù)邏輯,也不需要重用,只是一小部分 HTML 片段

      使用 ng-content 指令將父組件模板中的任意片段投影到它的子組件上

      組件里面的 ng-content 部分可以被組件外部包裹的元素替代

      // 表現(xiàn)形式: <ng-content select="樣式類(lèi)/HTML標(biāo)簽/指令"></ng-content>  <ng-content select="[appGridItem]"></ng-content>
      登錄后復(fù)制

      select 表明包含 appGridItem 的指令的元素才能投影穿透過(guò)來(lái)

      Angular指令

      深入了解Angular(新手入門(mén)指南)

      指令可以理解為沒(méi)有模版的組件,它需要一個(gè)宿主元素(Host)

      推薦使用方括號(hào) [] 指定 Selector,使它變成一個(gè)屬性

      @Directive({ selector: '[appGridItem]' })
      登錄后復(fù)制

      內(nèi)置屬性型指令

      NgClass

      ngClass 是自由度和拓展性最強(qiáng)的樣式綁定方式

      <div [ngClass]="{'red': true, 'blue': false}">   這是一個(gè) div </div>
      登錄后復(fù)制

      NgStyle

      ngStyle由于是嵌入式樣式,因此可能會(huì)覆蓋掉其他樣式,需謹(jǐn)慎

      <div [ngStyle]="{'background-color':'green'}">你好 ngStyle</div>
      登錄后復(fù)制

      NgModel

      // 注意引入:FormsModule import { FormsModule } from '@angular/forms';  <input type="text" [(ngModel)]="inputValue"/> {{inputValue}}
      登錄后復(fù)制

      內(nèi)置結(jié)構(gòu)型指令

      ngIf

      ngIf 根據(jù)表達(dá)式是否成立,決定是否展示 DOM 標(biāo)簽

      <p *ngIf="list.length > 3">這是 ngIF 判斷是否顯示</p>
      登錄后復(fù)制

      ngIf else

      <div *ngIf="show else ElseContent">這是 ngIF 內(nèi)容</div> <ng-template #ElseContent>   <h2>這是 else 內(nèi)容</h2> </ng-template>  // 結(jié)構(gòu)性指令都依賴(lài)于 ng-template,*ngIf 實(shí)際上就是 ng-template 指令的 [ngIf] 屬性。
      登錄后復(fù)制

      ngFor

      <ul>   <li *ngFor="let item of list;let i = index;">      {{item}} --{{i}}   </li> </ul>
      登錄后復(fù)制

      ngSwitch

      <ul [ngSwitch]="score">    <li *ngSwitchCase="1">已支付</li>    <li *ngSwitchCase="2">已確認(rèn)</li>    <li *ngSwitchCase="3">已發(fā)貨</li>    <li *ngSwitchDefault>已失效</li> </ul>
      登錄后復(fù)制

      指令事件樣式綁定

      @HostBinding 綁定宿主的屬性或者樣式

      @HostBinding('style.display') display = "grid";  // 用樣式綁定代替rd2的 this.setStyle('display','grid');
      登錄后復(fù)制

      @HostListener 綁定宿主的事件

      @HostListener('click',['$event.target'])  // 第一個(gè)參數(shù)是事件名,第二個(gè)是事件攜帶參數(shù)
      登錄后復(fù)制

      Angular生命周期

      生命周期函數(shù)通俗的講就是組件創(chuàng)建、組件更新、組件銷(xiāo)毀的時(shí)候會(huì)觸發(fā)的一系列的方法

      當(dāng) Angular 使用構(gòu)造函數(shù)新建一個(gè)組件或指令后,就會(huì)按下面規(guī)定的順序在特定時(shí)刻調(diào)用生命周期鉤子

      • constructor :構(gòu)造函數(shù)永遠(yuǎn)首先被調(diào)用,一般用于變量初始化以及類(lèi)實(shí)例化

      • ngOnChanges :被綁定的輸入屬性變化時(shí)被調(diào)用,首次調(diào)用一定在 ngOnInit 之前。輸入屬性發(fā)生變化是觸發(fā),但組件內(nèi)部改變輸入屬性是不會(huì)觸發(fā)的。注意:如果組件沒(méi)有輸入,或者使用它時(shí)沒(méi)有提供任何輸入,那么框架就不會(huì)調(diào)用 ngOnChanges

      • ngOnInit :組件初始化時(shí)被調(diào)用,在第一輪 ngOnChanges 完成之后調(diào)用,只調(diào)用一次。使用 ngOnInit 可以在構(gòu)造函數(shù)之后馬上執(zhí)行復(fù)雜的初始化邏輯,同時(shí)在 Angular 設(shè)置完輸入屬性之后,可以很安全的對(duì)該組件進(jìn)行構(gòu)建

      • ngDoCheck :臟值檢測(cè)時(shí)調(diào)用,在變更檢測(cè)周期中 ngOnChanges 和 ngOnInit 之后

        • ngAfterContentInit :內(nèi)容投影ng-content完成時(shí)調(diào)用,只在第一次 ngDoCheck 之后調(diào)用

        • ngAfterContentChecked: 每次完成被投影組件內(nèi)容的變更檢測(cè)之后調(diào)用(多次)

        • ngAfterViewInit :組件視圖及子視圖初始化完成時(shí)調(diào)用,只在第一次 ngAfterContentChecked 調(diào)用一次

        • ngAfterViewChecked: 檢測(cè)組件視圖及子視圖變化之后調(diào)用(多次)

      • ngOnDestroy 當(dāng)組件銷(xiāo)毀時(shí)調(diào)用,可以反訂閱可觀察對(duì)象和分離事件處理器,以防內(nèi)存泄漏

      Angular路由

      路由(導(dǎo)航)本質(zhì)上是切換視圖的一種機(jī)制,路由的導(dǎo)航URL并不真實(shí)存在

      Angular 的路由借鑒了瀏覽器URL變化導(dǎo)致頁(yè)面切換的機(jī)制

      Angular 是單頁(yè)程序,路由顯示的路徑不過(guò)是一種保存路由狀態(tài)的機(jī)制,這個(gè)路徑在 web 服務(wù)器上不存在

      路由基本配置

      /**  * 在功能模塊中定義子路由后,只要導(dǎo)入該模塊,等同于在根路由中直接定義  * 也就是說(shuō)在 AppModule 中導(dǎo)入 HomeModule 的時(shí)候,  * 由于 HomeModule 中導(dǎo)入了 HomeRouting Module  * 在 HomeRoutingModule 中定義的路由會(huì)合并到根路由表  * 相當(dāng)于直接在根模塊中定義下面的數(shù)組。  * const routes = [{  *   path: 'home',  *   component: HomeContainerComponent  * }]  */  const routes: Routes = [   {path: 'home', component: HomeComponent},   {path: 'news', component: NewsComponent},   {path: 'newscontent/:id', component: NewscontentComponent},  // 配置動(dòng)態(tài)路由   {     path: '',     redirectTo: '/home',  // 重定向     pathMatch: 'full' 	},   //匹配不到路由的時(shí)候加載的組件 或者跳轉(zhuǎn)的路由   {      path: '**', /*任意的路由*/      // component:HomeComponent      redirectTo:'home'   } ]  @NgModule({   /**    * 根路由使用 `RouterModule.forRoot(routes)` 形式。    * 而功能模塊中的路由模塊使用 `outerModule.forChild(routes)` 形式。    * 啟用路由的 debug 跟蹤模式,需要在根模塊中設(shè)置 `enableTracing: true`    */   imports: [RouterModule.forRoot(routes, { enableTracing: true })],   exports: [RouterModule] }) export class AppRoutingModule { }
      登錄后復(fù)制

      激活路由

      找到 app.component.html 根組件模板,配置 router-outlet

      通過(guò)模版屬性訪問(wèn)路由,即路由鏈接 routerLink

      <h1>   <a [routerLink]="['/home']">首頁(yè)</a>   <a [routerLink]="['/home',tab.link]">首頁(yè)</a><!-- 路徑參數(shù) -->   <a [routerLink]="['/home',tab.link,{name:'val1'}]">首頁(yè)</a> <!-- 路徑對(duì)象參數(shù) -->   <a [routerLink]="['/home']" [queryParams]="{name:'val1'}">首頁(yè)</a> <!-- 查詢(xún)參數(shù) --> </h1> <router-outlet></router-outlet>  <!-- 路由插座,占位標(biāo)簽 --> <!--   路由顯示的內(nèi)容是插入到 router-outlet 的同級(jí)的下方節(jié)點(diǎn)   而不是在 router-outlet 中包含 --> <!--   當(dāng)事件處理或者達(dá)到某個(gè)條件時(shí),可以使用手動(dòng)跳轉(zhuǎn) 	this.router.navigate(['home']);  	this.router.navigate(['home',tab.link]);  	this.router.navigate(['home',tab.link,{name:'val1'}]);  	this.router.navigate(['home'],{queryParams:{name:'val1'}});  -->
      登錄后復(fù)制

      控制路由激活狀態(tài)的樣式 routerLinkActive

      <h1>     <a routerLink="/home" routerLinkActive="active">首頁(yè)</a>     <a routerLink="/news" routerLinkActive="active">新聞</a> </h1>  <h1>    <a [routerLink]="[ '/home' ]" routerLinkActive="active">首頁(yè)</a>    <a [routerLink]="[ '/news' ]" routerLinkActive="active">新聞</a> </h1>  .active{    color:red; }
      登錄后復(fù)制

      路由參數(shù)

      路徑參數(shù)讀取

      this.route.paramsMap.subscribe(params => {...})
      登錄后復(fù)制

      查詢(xún)參數(shù)讀取

      this.route.queryParamsMap.subscribe(params => {...})
      登錄后復(fù)制

      路由傳遞一個(gè)參數(shù)及其接收方法:

      傳遞參數(shù):path:’info/:id’

      接收參數(shù):

      constructor(private routerInfo: ActivatedRoute){} ngOnInit(){ 	this.routerInfo.snapshot.params['id'] }
      登錄后復(fù)制

      路由傳遞多個(gè)參數(shù)及其接收方法:

      傳遞:[queryParams]=‘{id:1,name:‘crm’}’

      接收參數(shù):

      constructor(private routerInfo: ActivatedRoute){} ngOnInit(){ 	this.routerInfo.snapshot.params['id'] 	this.routerInfo.snapshot.params['name'] }
      登錄后復(fù)制

      路由懶加載

      懶加載子模塊,子模塊需要配置路由設(shè)置啟動(dòng)子模塊 loadChildren

      const routes: Routes = [     {path:'user',loadChildren:'./module/user/user.module#UserModule' },     {path:'product',loadChildren:'./module/product/product.module#ProductModule'},     {path:'article',loadChildren:'./module/article/article.module#ArticleModule'},     {path:'**',redirectTo:'user'} ];  // 上面好像會(huì)報(bào)錯(cuò) Error find module  // 配置懶加載 const routes: Routes = [     {path:'user',loadChildren:()=>import('./module/user/user.module').then(mod=>mod.UserModule)},     {path:'article',loadChildren:()=>import('./module/article/article.module').then(mod=>mod.ArticleModule)},     {path:'product',loadChildren:()=>import('./module/product/product.module').then(mod=>mod.ProductModule)},     {path:'**',redirectTo:'user'} ];
      登錄后復(fù)制

      Angular服務(wù)

      組件不應(yīng)該直接獲取或保存數(shù)據(jù),應(yīng)該聚焦于展示數(shù)據(jù),而把數(shù)據(jù)訪問(wèn)的職責(zé)委托給某個(gè)服務(wù)

      獲取數(shù)據(jù)和視圖展示應(yīng)該相分離,獲取數(shù)據(jù)的方法應(yīng)該放在服務(wù)中

      類(lèi)似 VueX,全局的共享數(shù)據(jù)(通用數(shù)據(jù))及非父子組件傳值、共享數(shù)據(jù)放在服務(wù)中

      組件之間相互調(diào)用各組件里定義的方法

      多個(gè)組件都用的方法(例如數(shù)據(jù)緩存的方法)放在服務(wù)(service)里

      import { Injectable } from '@angular/core'; @Injectable({   providedIn: 'root', }) export class HeroService {   aa = 'abc';   constructor(){ }   ngOnInit(){ } }  import { HeroService } from '../../../services/hero/hero.service'; export class AComponent implements OnInit{   constructor(private heroService : HeroService) {} //實(shí)例化   ngOnInit(){     console.log(this.heroService.aa)   } }
      登錄后復(fù)制

      @Injectable()裝飾器

      在 Angular 中,要把一個(gè)類(lèi)定義為服務(wù),就要用 @Injectable() 裝飾器來(lái)提供元數(shù)據(jù),以便讓 Angular 把它作為依賴(lài)注入到組件中。

      同樣,也要使用 @Injectable () 裝飾器來(lái)表明一個(gè)組件或其它類(lèi)(比如另一個(gè)服務(wù)、管道或 NgModule)擁有一個(gè)依賴(lài)。

      @Injectable () 裝飾器把這個(gè)服務(wù)類(lèi)標(biāo)記為依賴(lài)注入系統(tǒng)的參與者之一,它是每個(gè) Angular 服務(wù)定義中的基本要素。

      在未配置好 Angular 的依賴(lài)注入器時(shí),Angular 實(shí)際上無(wú)法將它注入到任何位置。

      @Injectable () 裝飾器具有一個(gè)名叫 providedIn 的元數(shù)據(jù)選項(xiàng),providedIn 設(shè)置為 'root',即根組件中,那么該服務(wù)就可以在整個(gè)應(yīng)用程序中使用了。

      providedIn 提供這些值:‘root' 、'platform''any' 、null

      對(duì)于要用到的任何服務(wù),必須至少注冊(cè)一個(gè)提供者。

      服務(wù)可以在自己的元數(shù)據(jù)中把自己注冊(cè)為提供者,可以讓自己隨處可用,也可以為特定的模塊或組件注冊(cè)提供者。

      要注冊(cè)提供者,就要在服務(wù)的 @Injectable () 裝飾器中提供它的元數(shù)據(jù),或者在 @NgModule ()@Component () 的元數(shù)據(jù)中。

      在組件中提供服務(wù)時(shí),還可以使用 viewProdivers,viewProviders 對(duì)子組件樹(shù)不可見(jiàn)

      可以使用不同層級(jí)的提供者來(lái)配置注入器,也表示該服務(wù)的作用范圍

      • Angular 創(chuàng)建服務(wù)默認(rèn)采用的方式:在服務(wù)本身的 @Injectable () 裝飾器中

      • 該服務(wù)只在某服務(wù)中使用:在 NgModule 的 @NgModule () 裝飾器中

      • 該服務(wù)在某組件中使用:在組件的 @Component () 裝飾器中

      依賴(lài)注入

      在項(xiàng)目中,有人提供服務(wù),有人消耗服務(wù),而依賴(lài)注入的機(jī)制提供了中間的接口,并替消費(fèi)者創(chuàng)建并初始化處理

      消費(fèi)者只需要知道拿到的是完整可用的服務(wù)就好,至于這個(gè)服務(wù)內(nèi)部的實(shí)現(xiàn),甚至是它又依賴(lài)了怎樣的其他服務(wù),都不需要關(guān)注。

      Angular 通過(guò) service共享狀態(tài),而這些管理狀態(tài)和數(shù)據(jù)的服務(wù)便是通過(guò)依賴(lài)注入的方式進(jìn)行處理的

      Angular 的 service 的本質(zhì)就是依賴(lài)注入,將service作為一個(gè)Injector注入到component

      歸根到底,很多時(shí)候我們創(chuàng)建服務(wù),是為了維護(hù)公用的狀態(tài)和數(shù)據(jù),通過(guò)依賴(lài)注入的方式來(lái)規(guī)定哪些組件可共享

      深入了解Angular(新手入門(mén)指南)

      正是因?yàn)?Angular 提供的這種依賴(lài)注入機(jī)制,才能在構(gòu)造函數(shù)中直接聲明實(shí)例化

        constructor(private heroService : HeroService) {} // 依賴(lài)注入
      登錄后復(fù)制

      深入了解Angular(新手入門(mén)指南)

      先看一下 Angular 中 TS 單文件的注入

      // 首先寫(xiě) @injectable 我們需要注入的東西,比如說(shuō) product @Injectable() class Product {   constructor(     private name: string,     private color: string,     private price: number,   ) { } }  class PurchaseOrder {   constructor(private product: Product){ } }   export class HomeGrandComponent implements OnInit {   constructor() { }   ngOnInit() {     // 構(gòu)造一個(gè) injector 用 create 方法 里面 providers 數(shù)組中寫(xiě)我們需要構(gòu)造的東西     const injector = Injector.create({       providers: [         {           provide: Product,           // 構(gòu)造 Product 在 useFactory 中就會(huì)把上面定義的 product 注入到這里           useFactory: () => {             return new Product('大米手機(jī)', '黑色', 2999);           },           deps: []         },         {           provide: PurchaseOrder,           deps: [Product]         },         {           provide: token,           useValue: { baseUrl: 'http://local.dev' }         }       ]     });      console.log('injector獲取product', injector.get(PurchaseOrder).getProduct);     console.log(injector.get(token));   }
      登錄后復(fù)制

      再看一下Angular 中 module 模塊的注入

      // .service.ts 中 @Injectable () 依賴(lài)注入 @Injectable() export class HomeService {   imageSliders: ImageSlider[] = [     {       imgUrl:'',       link: '',       caption: ''     }   ]   getBanners() {     return this.imageSliders;   } }  // 使用模塊對(duì)應(yīng)的.module.ts 中 @NgModule({   declarations: [     HomeDetailComponent,   ],   providers:[HomeService], // 在 providers 直接寫(xiě)對(duì)應(yīng)服務(wù),直接將服務(wù)注入模塊   imports: [SharedModule, HomeRoutingModule] })
      登錄后復(fù)制

      不管是在組件內(nèi)還是在模塊內(nèi),我們使用 providers 的時(shí)候,就是進(jìn)行了一次依賴(lài)注入的注冊(cè)和初始化

      其實(shí)模塊類(lèi)(NgModule)也和組件一樣,在依賴(lài)注入中是一個(gè)注入器,作為容器提供依賴(lài)注入的接口

      NgModule 使我們不需要在一個(gè)組件中注入另一個(gè)組件,通過(guò)模塊類(lèi)(NgModule)可以進(jìn)行獲取和共享

      Angular 管道

      Angular 管道是編寫(xiě)可以在 HTML 組件中聲明的顯示值轉(zhuǎn)換的方法

      管道將數(shù)據(jù)作為輸入并將其轉(zhuǎn)換為所需的輸出

      管道其實(shí)就是過(guò)濾器,用來(lái)轉(zhuǎn)換數(shù)據(jù)然后顯示給用戶(hù)

      管道將整數(shù)、字符串、數(shù)組和日期作為輸入,用 | 分隔,然后根據(jù)需要轉(zhuǎn)換格式,并在瀏覽器中顯示出來(lái)

      在插值表達(dá)式中,可以定義管道并根據(jù)情況使用

      Angular 應(yīng)用程序中可以使用許多類(lèi)型的管道

      內(nèi)置管道

      • String -> String
        • UpperCasePipe 轉(zhuǎn)換成大寫(xiě)字符
        • LowerCasePipe 轉(zhuǎn)換成小寫(xiě)字符
        • TitleCasePipe 轉(zhuǎn)換成標(biāo)題形式,第一個(gè)字母大寫(xiě),其余小寫(xiě)
      • Number -> String
        • DecimalPipe 根據(jù)數(shù)字選項(xiàng)和區(qū)域設(shè)置規(guī)則格式化值
        • PercentPipe 將數(shù)字轉(zhuǎn)換為百分比字符串
        • CurrencyPipe 改變?nèi)嗣麕鸥袷?/li>
      • Object -> String
        • JsonPipe 對(duì)象序列化
        • DatePipe 日期格式轉(zhuǎn)換
      • Tools
        • SlicePipe 字符串截取
        • AsyncPipe 從異步回執(zhí)中解出一個(gè)值
        • I18nPluralPipe 復(fù)數(shù)化
        • I18nSelectPipe 顯示與當(dāng)前值匹配的字符串

      使用方法

      <div>{{ 'Angular' | uppercase }}</div>  <!-- Output: ANGULAR -->  <div>{{ data | date:'yyyy-MM-dd' }}</div>  <!-- Output: 2022-05-17 -->  <div>{{ { name: 'ccc' } | json }}</div>  <!-- Output: { "name": "ccc" } -->  <!--  	管道可以接收任意數(shù)量的參數(shù),使用方式是在管道名稱(chēng)后面添加: 和參數(shù)值 	若需要傳遞多個(gè)參數(shù)則參數(shù)之間用冒號(hào)隔開(kāi)  -->  <!-- 可以將多個(gè)管道連接在一起,組成管道鏈對(duì)數(shù)據(jù)進(jìn)行處理 --> <div>{{ 'ccc' | slice:0:1 | uppercase }}</div>
      登錄后復(fù)制

      自定義管道

      管道本質(zhì)上就是個(gè)類(lèi),在這個(gè)類(lèi)里面去實(shí)現(xiàn) PipeTransfrom 接口的 transform 這個(gè)方法

      • 使用 @Pipe 裝飾器定義 Pipemetadata 信息,如 Pipe 的名稱(chēng) – 即 name 屬性
      • 實(shí)現(xiàn) PipeTransform 接口中定義的 transform 方法

      // 引入PipeTransform是為了繼承transform方法 import { Pipe, PipeTransform } form '@angular/core';  // name屬性值慣用小駝峰寫(xiě)法, name的值為html中 | 后面的名稱(chēng) @Pipe({ name: 'sexReform' })  export class SexReformPipe implements PipeTransform {     transform(value: string, args?: any): string {     // value的值為html中 | 前面?zhèn)魅氲闹担?args為名稱(chēng)后傳入的參數(shù)         switch(value){             case 'male': return '男';             case 'female': return '女';             default: return '雌雄同體';         }      } }  // demo.component.ts export Class DemoComponent {     sexValue = 'female'; }  // demo.component.html <span>{{ sexValue | sexReform }}</span>  // 瀏覽器輸出 女  // 管道可以鏈?zhǔn)绞褂茫€可以傳參 <span> {{date | date: 'fullDate' | uppercase}} </span> // 每一個(gè)自定義管道都需要實(shí)現(xiàn) PipeTransform 接口,這個(gè)接口非常簡(jiǎn)單,只需要實(shí)現(xiàn) transform 方法即可。 // transform()方法參數(shù)格式 - transform(value: string, args1: any, args2?: any):  // value為傳入的值(即為需要用此管道處理的值, | 前面的值);  // args 為傳入的參數(shù)(?:代表可選); // html 中使用管道格式 - {{ 數(shù)據(jù) | 管道名 : 參數(shù)1 : 參數(shù)2 }} // 與 component 一樣,pipe 需要先在 declarations 數(shù)組中聲明后使用
      登錄后復(fù)制

      Angular操作DOM

      原生JS操作

      ngAfterViewInit(){    var boxDom:any=document.getElementById('box');    boxDom.style.color='red'; }
      登錄后復(fù)制

      ElementRef

      ElementRef 是對(duì)視圖中某個(gè)原生元素的包裝類(lèi)

      因?yàn)?DOM 元素不是 Angular 中的類(lèi),所以需要一個(gè)包裝類(lèi)以便在 Angular 中使用和標(biāo)識(shí)其類(lèi)型

      ElementRef 的背后是一個(gè)可渲染的具體元素。在瀏覽器中,它通常是一個(gè) DOM 元素

      class ElementRef<T> {   constructor(nativeElement: T)   nativeElement: T  //背后的原生元素,如果不支持直接訪問(wèn)原生元素,則為 null(比如:在 Web Worker 環(huán)境下運(yùn)行此應(yīng)用的時(shí)候)。 }
      登錄后復(fù)制

      當(dāng)需要直接訪問(wèn) DOM 時(shí),請(qǐng)把本 API 作為最后選擇 。優(yōu)先使用 Angular 提供的模板和數(shù)據(jù)綁定機(jī)制

      如果依賴(lài)直接訪問(wèn) DOM 的方式,就可能在應(yīng)用和渲染層之間產(chǎn)生緊耦合。這將導(dǎo)致無(wú)法分開(kāi)兩者,也就無(wú)法將應(yīng)用發(fā)布到 Web Worker 中

      ViewChild

      使用模板和數(shù)據(jù)綁定機(jī)制,使用 @viewChild

      // 模版中給 DOM 起一個(gè)引用名字,以便可以在組件類(lèi)或模版中進(jìn)行引用 <div #myattr></div>  // 引入 ViewChild import { ViewChild,ElementRef } from '@angular/core';  // 用 ViewChild 綁定 DOM	 @ViewChild('myattr') myattr: ElementRef;  // 在 ngAfterViewInit 生命周期函數(shù)里可以很安全的獲取 ViewChild 引用的 DOM ngAfterViewInit(){    let attrEl = this.myattr.nativeElement; }
      登錄后復(fù)制

      父組件中可以通過(guò) ViewChild 調(diào)用子組件的方法

      // 給子組件定義一個(gè)名稱(chēng) <app-footer #footerChild></app-footer>  // 引入 ViewChild import { Component, OnInit ,ViewChild} from '@angular/core';  // ViewChild 和子組件關(guān)聯(lián)起來(lái)  // 如果想引用模版中的 Angular 組件,ViewChild 中可以使用引用名,也可以使用組件類(lèi)型 @ViewChild('footerChild') footer;  // @ViewChild('imageSlider', { static: true }) // static指定是動(dòng)態(tài)還是靜態(tài),在*ngFor或者*ngIf中是動(dòng)態(tài),否則即為靜態(tài),動(dòng)態(tài)為 true  // 調(diào)用子組件 run(){    this.footer.footerRun(); }
      登錄后復(fù)制

      引用多個(gè)模版元素,可以用@ViewChildren,在ViewChildren中可以使用引用名

      或者使用 Angular 組件/指令的類(lèi)型,聲明類(lèi)型為 QueryList<?>

      <img   #img   *ngFor="let slider of sliders"   [src]="slider.imgUrl"   [alt]="slider.capiton" >  // 使用 ViewChildren 引用獲取 @ViewChildren(’img‘);  // 使用類(lèi)型引用獲取 imgs: QueryList<ElementRef>;
      登錄后復(fù)制

      Renderer2

      Renderer2 是 Angular 提供的操作 element 的抽象類(lèi),使用該類(lèi)提供的方法,能夠?qū)崿F(xiàn)在不直接接觸 DOM 的情況下操作頁(yè)面上的元素。

      Renderer2 的常用方法:

      • addClass /removeClassdirective 的宿主元素添加或刪除 class

      import { Directive, Renderer2, ElementRef, OnInit } from '@angular/core';  @Directive({     selector: '[testRenderer2]' })  export class TestRenderer2Directive implements OnInit {     constructor(private renderer: Renderer2, private el: ElementRef) {} // 實(shí)例化      ngOnInit() {     this.renderer.addClass(this.el.nativeElement, 'test-renderer2');     // this.renderer.removeClass(this.el.nativeElement, 'old-class');     } }
      登錄后復(fù)制

      • createElement /appendChild/createText 創(chuàng)建 DIV 元素,插入文本內(nèi)容,并將其掛載到宿主元素上

      import { Directive, Renderer2, ElementRef, OnInit } from '@angular/core';  constructor(private renderer: Renderer2, private el: ElementRef) {}  ngOnInit() {     const div = this.renderer.createElement('div');     const text = this.renderer.createText('Hello world!');          this.renderer.appendChild(div, text);     this.renderer.appendChild(this.el.nativeElement, div); }
      登錄后復(fù)制

      • setAttribute /removeAttribute 在宿主元素上添加或刪除 attribute

      import { Directive, Renderer2, ElementRef, OnInit } from '@angular/core';  constructor(private renderer: Renderer2, private el: ElementRef) {}  ngOnInit() {     this.renderer.setAttribute(this.el.nativeElement, 'aria-hidden', 'true'); }
      登錄后復(fù)制

      • setStyle /removeStyle 在宿主元素上添加 inline-style

      import { Directive, Renderer2, ElementRef, OnInit } from '@angular/core';  constructor(private renderer: Renderer2, private el: ElementRef) {}  ngOnInit() {     this.renderer.setStyle(         this.el.nativeElement,         'border-left',         '2px dashed olive'     ); }
      登錄后復(fù)制

      移除 inline-style :

      constructor(private renderer: Renderer2, private el: ElementRef) {}  ngOnInit() {     this.renderer.removeStyle(this.el.nativeElement, 'border-left'); }
      登錄后復(fù)制

      • setProperty 設(shè)置宿主元素的 property 的值

      constructor(private renderer: Renderer2, private el: ElementRef) {}  ngOnInit() {     this.renderer.setProperty(this.el.nativeElement, 'alt', 'Cute alligator'); }
      登錄后復(fù)制

      直接操作DOM,Angular不推薦。盡量采用 @viewChildrenderer2 組合,Angular推薦使用 constructor(private rd2: Renderer2) {} 依賴(lài)注入,

      import {   Component,   OnInit,   Renderer2,   ViewChild, } from '@angular/core'; import { AboxItemComponent } from './abox-item/abox-item.component';   @Component({   selector: 'app-abox',   templateUrl: './abox.component.html',   styleUrls: ['./abox.component.less'], }) export class AboxComponent implements OnInit {   private container;   activeIndex: number;   @ViewChild('containers') containers: any;   constructor(private rd2: Renderer2) {}     ngOnInit(): void {}     ngAfterViewInit(): void {     this.container = this.containers.nativeElement;     this.initCarouselWidth();   }        initCarouselWidth() {     this.rd2.setStyle(this.container, 'width', '100px');   } }
      登錄后復(fù)制

      Angular網(wǎng)絡(luò)請(qǐng)求

      HttpClient

      需導(dǎo)入 HttpClientModule ,只在根模塊中導(dǎo)入,并且整個(gè)應(yīng)用只需導(dǎo)入一次,不用在其他模塊導(dǎo)入

      在構(gòu)造函數(shù)中注入HttpClient,get/post方法對(duì)應(yīng)HTTP方法,這些方法是泛型的,可以直接把返回的JSON轉(zhuǎn)換成對(duì)應(yīng)類(lèi)型。若是不規(guī)范的請(qǐng)求,使用request方法

      返回的值是 Observable,必須訂閱才會(huì)發(fā)送請(qǐng)求,否則不會(huì)發(fā)送

      get 請(qǐng)求數(shù)據(jù)

      // 在 app.module.ts 中引入 HttpClientModule 并注入 import {HttpClientModule} from '@angular/common/http'; imports: [   BrowserModule,   HttpClientModule ]  // 在用到的地方引入 HttpClient 并在構(gòu)造函數(shù)聲明 import {HttpClient} from "@angular/common/http"; constructor(private http: HttpClient,private cd: ChangeDetectorRef) { } // 依賴(lài)注入  // get 請(qǐng)求數(shù)據(jù) var api = "http://baidu.com/api/productlist"; this.http.get(api).subscribe(response => {   console.log(response);   this.cd.markForCheck();   // 如果改變了臟值檢測(cè)的變更原則 changeDetection: ChangeDetectionStrategy.OnPush   // 則需要使用 this.cd.markForCheck() 手動(dòng)提醒 Angular 這里需要進(jìn)行臟值檢測(cè) });
      登錄后復(fù)制

      post 提交數(shù)據(jù)

      // 在 app.module.ts 中引入 HttpClientModule 并注入 import {HttpClientModule} from '@angular/common/http'; imports: [    BrowserModule,    HttpClientModule ]  // 在用到的地方引入 HttpClient 、HttpHeaders 并在構(gòu)造函數(shù)聲明 HttpClient import {HttpClient,HttpHeaders} from "@angular/common/http"; constructor(private http:HttpClient) { } // 實(shí)例化  // post 提交數(shù)據(jù) const httpOptions = {     headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; var api = "http://127.0.0.1:4200/doLogin"; this.http.post(api,{username:'瑞萌萌',age:'22'},httpOptions).subscribe(response => { 		console.log(response); });
      登錄后復(fù)制

      Jsonp請(qǐng)求數(shù)據(jù)

      // 在 app.module.ts 中引入 HttpClientModule、HttpClientJsonpModule 并注入 import {HttpClientModule,HttpClientJsonpModule} from'@angular/common/http'; imports: [    BrowserModule,    HttpClientModule,    HttpClientJsonpModule ]  // 在用到的地方引入 HttpClient 并在構(gòu)造函數(shù)聲明 import {HttpClient} from "@angular/common/http"; constructor(private http:HttpClient) { } // 實(shí)例化  // jsonp 請(qǐng)求數(shù)據(jù) var api = "http://baidu.com/api/productlist"; this.http.jsonp(api,'callback').subscribe(response => {    console.log(response); });
      登錄后復(fù)制

      攔截器

      Angular 攔截器是 Angular 應(yīng)用中全局捕獲和修改 HTTP 請(qǐng)求和響應(yīng)的方式,例如攜帶 Token 和捕獲 Error

      前提是只能攔截使用 HttpClientModule 發(fā)出的請(qǐng)求,如果使用 axios 則攔截不到

      創(chuàng)建攔截器

      // 使用命令 ng g interceptor name,在這里創(chuàng)建攔截器 ng g interceptor LanJieQi // cli 生成攔截器是沒(méi)有簡(jiǎn)寫(xiě)方式的  import { Injectable } from '@angular/core'; import {   HttpRequest,   HttpHandler,   HttpEvent,   HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs';  @Injectable() export class LanJieQiInterceptor implements HttpInterceptor {   constructor() {}   // 默認(rèn)的 intercept() 方法只是單純的將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)攔截器(如果有),并最終返回 HTTP 響應(yīng)體的 Observable   // request: HttpRequest<unknown> 表示請(qǐng)求對(duì)象,包含了請(qǐng)求相關(guān)的所有信息,unknown指定請(qǐng)求體body的類(lèi)型   // next: HttpHandler 請(qǐng)求對(duì)象修改完成,將修改后的請(qǐng)求對(duì)象通過(guò)next中的handle方法傳回真正發(fā)送請(qǐng)求的方法中   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> 	{     // next 對(duì)象表示攔截器鏈表中的下一個(gè)攔截器(在應(yīng)用中可以設(shè)置多個(gè)攔截器)     return next.handle(request);   } }
      登錄后復(fù)制

      注入攔截器

      // 在 @NgModule 模塊中注入攔截器 // 攔截器也是一個(gè)由 Angular 依賴(lài)注入 (DI) 系統(tǒng)管理的服務(wù),也必須先提供這個(gè)攔截器類(lèi),才能使用它 // 由于攔截器是 HttpClient 服務(wù)的依賴(lài),所以必須在提供 HttpClient 的同一個(gè)(或其各級(jí)父注入器)注入器中提供這些攔截器 @NgModule({   imports: [     HttpClientModule     // others...   ],   providers: [     {       provide: HTTP_INTERCEPTORS,       useClass: LanJieQiInterceptor,       // multi: true 表明 HTTP_INTERCEPTORS 是一個(gè)多重提供者的令牌,表示這個(gè)令牌可以注入多個(gè)攔截器       multi: true     },   ],   bootstrap: [AppComponent] })  export class AppModule { }
      登錄后復(fù)制

      請(qǐng)求頭攔截

      @Injectable()export class LanJieQiInterceptor implements HttpInterceptor {   constructor() {}   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> 	{     // 為了統(tǒng)一設(shè)置請(qǐng)求頭,需要修改請(qǐng)求     // 但 HttpRequest 和 HttpResponse 實(shí)例的屬性卻是只讀(readonly)的     // 所以修改前需要先 clone 一份,修改這個(gè)克隆體后再把它傳給 next.handle()     let req = request.clone({     	setHeaders:{       	token:"123456" // 在請(qǐng)求頭中增加 token:123456     	} 			// setHeaders 和 headers: request.headers.set('token', '123456') 一致   	})   	return next.handle(req)// 將修改后的請(qǐng)求返回給應(yīng)用   }}
      登錄后復(fù)制

      響應(yīng)捕獲

      @Injectable() export class LanJieQiInterceptor implements HttpInterceptor {   constructor() {}   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> 	{     // 為了統(tǒng)一設(shè)置請(qǐng)求頭,需要修改請(qǐng)求     // 但 HttpRequest 和 HttpResponse 實(shí)例的屬性卻是只讀(readonly)的     // 所以修改前需要先 clone 一份,修改這個(gè)克隆體后再把它傳給 next.handle()     let req = request.clone({     	setHeaders:{       	token:"123456" // 在請(qǐng)求頭中增加 token:123456     	} 			// setHeaders 和 headers: request.headers.set('token', '123456') 一致   	})   	return next.handle(req)// 將修改后的請(qǐng)求返回給應(yīng)用   } }
      登錄后復(fù)制

      如果有多個(gè)攔截器,請(qǐng)求順序是按照配置順序執(zhí)行,響應(yīng)攔截則是相反的順序

      如果提供攔截器的順序是先 A再 B再 C,那么請(qǐng)求階段的執(zhí)行順序就是 A->B->C,而響應(yīng)階段的執(zhí)行順序則是 C->B->A

      Angular表單

      模版驅(qū)動(dòng)表單

      模板驅(qū)動(dòng)表單在往應(yīng)用中添加簡(jiǎn)單的表單時(shí)非常有用,但是不像響應(yīng)式表單那么容易擴(kuò)展

      如果有非?;镜谋韱涡枨蠛秃?jiǎn)單到能用模板管理的邏輯,就使用模板驅(qū)動(dòng)表單

      響應(yīng)式表單和模板驅(qū)動(dòng)表單共享了一些底層構(gòu)造塊:

      FormControl 實(shí)例用于追蹤單個(gè)表單控件的值和驗(yàn)證狀態(tài)

      FormGroup 用于追蹤一個(gè)表單控件組的值和狀態(tài)

      FormArray 用于追蹤表單控件數(shù)組的值和狀態(tài),有長(zhǎng)度屬性,通常用來(lái)代表一個(gè)可以增長(zhǎng)的字段集合

      ControlValueAccessor 用于在 Angular 的 FormControl 實(shí)例和原生 DOM 元素之間創(chuàng)建一個(gè)橋梁

      FormControlFormGroup 是 angular 中兩個(gè)最基本的表單對(duì)象

      FormControl 代表單一的輸入字段,它是 Angular 表單中最小單員,它封裝了這些字段的值和狀態(tài),比如是否有效、是否臟(被修改過(guò))或是否有錯(cuò)誤等

      FormGroup 可以為一組 FormControl 提供總包接口(wrapper interface),來(lái)管理多個(gè) FormControl

      當(dāng)我們?cè)噲D從 FormGroup 中獲取 value 時(shí),會(huì)收到一個(gè) “鍵值對(duì)” 結(jié)構(gòu)的對(duì)象

      它能讓我們從表單中一次性獲取全部的值而無(wú)需逐一遍歷 FormControl,使用起來(lái)相當(dāng)順手

      FormGroupFormControl 都繼承自同一個(gè)祖先 AbstractControltractControl(這是 FormControl,FormGroupFormArray 的基類(lèi))

      首先加載 FormsModule

      // 先在 NgModule 中導(dǎo)入了 FormsModule 表單庫(kù) // FormsModule 為我們提供了一些模板驅(qū)動(dòng)的指令,例如:ngModel、NgForm import {    FormsModule } from '@angular/forms';   @NgModule({    declarations: [      FormsDemoApp,      DemoFormSku,      // ... our declarations here    ],    imports: [      BrowserModule,      FormsModule,   ],    bootstrap: [ FormsDemoApp ]  })  class FormsDemoAppModule {}
      登錄后復(fù)制

      接下來(lái)創(chuàng)建一個(gè)模版表單

       <div>       <h2>基礎(chǔ)表單:商品名稱(chēng)</h2>       <form #f="ngForm" (ngSubmit)="onSubmit(f.value)">         <div class="sku">           <label for="skuInput">商品名稱(chēng):</label>           <input             type="text"             id="skuInput"             placeholder="商品名稱(chēng)"             name="sku" //使用form時(shí)必須定義,可以理解為當(dāng)前控件的名字             ngModel           />         </div>         <button>提交</button>       </form>     </div>
      登錄后復(fù)制

      我們導(dǎo)入了 FormsModule,因此可以在視圖中使用 NgForm

      當(dāng)這些指令在視圖中可用時(shí),它就會(huì)被附加到任何能匹配其 selector 的節(jié)點(diǎn)上

      NgForm 做了一件便利但隱晦的工作:它的選擇器包含 form 標(biāo)簽(而不用顯式添加 ngForm 屬性)

      這意味著當(dāng)導(dǎo)入 FormsModule 時(shí)候,NgForm 就會(huì)被自動(dòng)附加到視圖中所有的標(biāo)簽上

      NgForm 提供了兩個(gè)重要的功能:

      • 一個(gè) ngFormFormGroup 對(duì)象
      • 一個(gè)輸出事件 (ngSubmit)

       <form #f="ngForm" (ngSubmit)="onSubmit(f.value)" >  <!--  	這里使用了 #f=“ngForm”,#v=thing 的意思是我們希望在當(dāng)前視圖中創(chuàng)建一個(gè)局部變量 	這里為視圖中的 ngForm 創(chuàng)建了一個(gè)別名,并綁定到變量 #f 	這個(gè) ngForm 是由 NgForm 指令導(dǎo)出的 	ngForm 的類(lèi)型的對(duì)象是 FormGroup 類(lèi)型的 	這意味著可以在視圖中把變量 f 當(dāng)作 FormGroup 使用,而這也正是我們?cè)谳敵鍪录?(ngSubmit) 中的使用方法 	在表單中綁定 ngSubmit 事件 (ngSubmit)=“onSubmit (f.value)“ 	(ngSubmit) 來(lái)自 NgForm 指令 	onSubmit() 將會(huì)在組件類(lèi)中進(jìn)行定義 	f 就是 FormGroup ,而 .value 會(huì)以鍵值對(duì)的形式返回 FormGroup 中所有控件的值 	 	總結(jié):當(dāng)提交表單時(shí),將會(huì)以該表單的值作為參數(shù),調(diào)用組件實(shí)例上的 `onSubmit` 方法 -->
      登錄后復(fù)制

      NgModel 會(huì)創(chuàng)建一個(gè)新的 FormControl 對(duì)象,把它自動(dòng)添加到父 FormGroup 上(這里也就是 form 表單對(duì)象)

      并把這個(gè) FormControl 對(duì)象綁定到一個(gè) DOM 上

      也就是說(shuō),它會(huì)在視圖中的 input 標(biāo)簽和 FormControl 對(duì)象之間建立關(guān)聯(lián)

      這種關(guān)聯(lián)是通過(guò) name 屬性建立的,在本例中是 "name"

      響應(yīng)式表單

      使用 ngForm 構(gòu)建 FormControlFormGroup 很方便,但是無(wú)法提供定制化選項(xiàng),因此引入響應(yīng)式表單

      響應(yīng)式表單提供了一種模型驅(qū)動(dòng)的方式來(lái)處理表單輸入,其中的值會(huì)隨時(shí)間而變化

      使用響應(yīng)式表單時(shí),通過(guò)編寫(xiě) TypeScript 代碼而不是 HTML 代碼來(lái)創(chuàng)建一個(gè)底層的數(shù)據(jù)模型

      在這個(gè)模型定義好以后,使用一些特定的指令將模板上的 HTML 元素與底層的數(shù)據(jù)模型連接在一起

      FormBuilder 是一個(gè)名副其實(shí)的表單構(gòu)建助手(可以把他看作一個(gè) “工廠” 對(duì)象)

      在先前的例子中添加一個(gè) FormBuilder,然后在組件定義類(lèi)中使用 FormGroup

      // 先在 NgModule 中導(dǎo)入了 ReactiveFormsModule 表單庫(kù) import {    ReactiveFormsModule  } from '@angular/forms';  @NgModule({   imports: [     FormsModule,     ReactiveFormsModule   ] })   // 使用 formGroup 和 formControl 指令來(lái)構(gòu)建這個(gè)組件,需要導(dǎo)入相應(yīng)的類(lèi) import {    FormBuilder,    FormGroup,   ReactiveFormsModule } from '@angular/forms';   // 在組件類(lèi)上注入一個(gè)從 FormBuilder 類(lèi)創(chuàng)建的對(duì)象實(shí)例,并把它賦值給 fb 變量(來(lái)自構(gòu)造函數(shù)) export class DemoFormSkuBuilder {    myForm: FormGroup;  // myForm 是 FormGroup 類(lèi)型   constructor(fb: FormBuilder) {      // FormBuilder 中的 group 方法用于創(chuàng)建一個(gè)新的 FormGroup     // group 方法的參數(shù)是代表組內(nèi)各個(gè) FormControl 的鍵值對(duì)     this.myForm = fb.group({  // 調(diào)用 fb.group () 來(lái)創(chuàng)建 FormGroup       // 設(shè)置一個(gè)名為 sku 的控件,控件的默認(rèn)值為 "123456"       'sku': ['123456']      });    }   onSubmit(value: string): void {      console.log('submit value:', value);    }  }
      登錄后復(fù)制

      在視圖表單中使用自定義的 FormGroup

      <h2 class="ui header">Demo Form: Sku with Builder</h2> <!--   	當(dāng)導(dǎo)入 FormsModule 時(shí),ngForm 就會(huì)自動(dòng)創(chuàng)建它自己的 FormGroup 	但這里不希望使用外部的 FormGroup,而是使用 FormBuilder 創(chuàng)建這個(gè) myForm 實(shí)例變量 	Angular提供了 formGroup 指令,能讓我們使用現(xiàn)有的 FormGroup 	NgForm 不會(huì)應(yīng)用到帶 formGroup 屬性的節(jié)點(diǎn)上 	這里我們告訴Angular,想用 myForm 作為這個(gè)表單的 FormGroup --> <form [formGroup]="myForm"    <label for="skuInput"> SKU </label>    <input type="text"       id="skuInput"       placeholder="SKU"       [formControl]="myForm.controls['sku']"> <!--   	將 FormControl 綁定到 input 標(biāo)簽上 :  	ngModel 會(huì)創(chuàng)建一個(gè)新的 FormControl 對(duì)象并附加到父 FormGroup 中 	但在例子中,我們已經(jīng)用 FormBuilder 創(chuàng)建了自己的 FormControl 	要將現(xiàn)有的 FormControl 綁定到 input 上,可以用 formControl 指令 	將 input 標(biāo)簽上的 formControl 指令指向 myForm.controls 上現(xiàn)有的 FormControl 控件 sku   -->
      登錄后復(fù)制

      記住以下兩點(diǎn):

      1. 如果想隱式創(chuàng)建新的 FormGroup 和 FormControl,使用:ngForm、ngModel
      2. 如果要綁定一個(gè)現(xiàn)有的 FormGroup 和 FormControl,使用:formGroup、formControl

      表單驗(yàn)證

      用戶(hù)輸入的數(shù)據(jù)格式并不總是正確的,如果有人輸入錯(cuò)誤的數(shù)據(jù)格式,我們希望給他反饋并阻止他提交表單

      因此,我們要用到驗(yàn)證器,由 validators 模塊提供

      Validators.required 是最簡(jiǎn)單的驗(yàn)證,表明指定的字段是必填項(xiàng),否則就認(rèn)為 FormControl 是無(wú)效的

      如果 FormGroup 中有一個(gè) FormControl 是無(wú)效的, 那整個(gè) FormGroup 都是無(wú)效的

      要為 FormControl 對(duì)象分配一個(gè)驗(yàn)證器 ,可以直接把它作為第二個(gè)參數(shù)傳給 FormControl 的構(gòu)造函數(shù)

      const control = new FormControl('name', Validators.required);  // 在組件定義類(lèi)中使用 FormBuilder   constructor(fb: FormBuilder) {      this.myForm = fb.group({        'name': ['',Validators.required]      });      this.name = this.myForm.controls['name'];    }
      登錄后復(fù)制

      在視圖中檢查驗(yàn)證器的狀態(tài),并據(jù)此采取行動(dòng)

      template:`<div>       <h2>商品表單:商品名稱(chēng)</h2>       <form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)">         <div>           <label for="nameInput">商品名稱(chēng):</label>           <input             type="text"             id="nameInput"             placeholder="請(qǐng)輸入名稱(chēng)"             [formControl]="myForm.controls['name']"           />           <div style="color:red" *ngIf="!name.valid">             名稱(chēng)無(wú)效           </div>           <div style="color:red" *ngIf="name.hasError('textinvalid')">             名稱(chēng)不是以“123”開(kāi)頭           </div>           <div *ngIf="name.dirty">             數(shù)據(jù)已變動(dòng)           </div>         </div>         <div>           <label for="codeInput">商品料號(hào):</label>           <input             type="text"             id="codeInput"             placeholder="請(qǐng)輸入料號(hào)"             [formControl]="myForm.controls['code']"           />           <div             style="color:red"             *ngIf="myForm.controls.code.hasError('required')"           >             該項(xiàng)必填           </div>           <div             style="color:red"             *ngIf="myForm.controls.code.hasError('pattern')"           >             只可輸入數(shù)字和英文           </div>         </div>         <div style="color:green" *ngIf="myForm.isvalid">           表單無(wú)效         </div>         <div style="color:green" *ngIf="myForm.valid">           表單有效         </div>         <button type="submit">提交</button>       </form>     </div>` export class NonInWarehouseComponent implements OnInit {   myForm: FormGroup;   name: AbstractControl;   constructor(fb: FormBuilder) {     this.myForm = fb.group({       name: ['牛奶', Validators.compose([Validators.required, textValidator])],       code: ['', [Validators.required, Validators.pattern('^[A-Za-z0-9]*$')]],     });     this.name = this.myForm.controls.name;   }   ngOnInit() {     const nameControl = new FormControl('nate');     console.log('nameControl', nameControl);   }   onSubmit(a: any) {     console.log('a', a);   } }
      登錄后復(fù)制

      內(nèi)置校驗(yàn)器

      Angular 提供了幾個(gè)內(nèi)置校驗(yàn)器,下面是比較常用的校驗(yàn)器:

      • Validators.required – 表單控件值非空
      • Validators.email – 表單控件值的格式是 email
      • Validators.minLength() – 表單控件值的最小長(zhǎng)度
      • Validators.maxLength() – 表單控件值的最大長(zhǎng)度
      • Validators.pattern() – 表單控件的值需匹配 pattern 對(duì)應(yīng)的模式(正則表達(dá)式)

      自定義驗(yàn)證器

      假設(shè)我們的 name 有特殊的驗(yàn)證需求,比如 name 必須以 123 作為開(kāi)始

      當(dāng)輸入值(控件的值 control.value)不是以 123 作為開(kāi)始時(shí),驗(yàn)證器會(huì)返回錯(cuò)誤代碼 invalidSku

      // angular 源代碼中實(shí)現(xiàn) Validators.required  export class Validators {   // 接收一個(gè) AbstractControl 對(duì)象作為輸入 	static required(control: AbstractControl): ValidationErrors | null; } // 當(dāng)驗(yàn)證器失敗時(shí),會(huì)返回一個(gè) String Map<string,any> 對(duì)象,他的鍵是” 錯(cuò)誤代碼 “,它的值是 true export declare type ValidationErrors = {     [key: string]: any; };  // 自定義驗(yàn)證器 function textValidator(   controls: FormControl // 因?yàn)镕ormControl繼承于 AbstractControl 所以也可以寫(xiě)成FormControl對(duì)象 ): {   [s: string]: boolean; } {   if (!controls.value.match(/^123/)) {     return { textinvalid: true };   } }
      登錄后復(fù)制

      FormControl 分配驗(yàn)證器,但是 name 已經(jīng)有一個(gè)驗(yàn)證器了,如何在同一個(gè)字段上添加多個(gè)驗(yàn)證器

      Validators.compose 來(lái)實(shí)現(xiàn)

      Validators.compose 把兩個(gè)驗(yàn)證器包裝在一起,我們可以將其賦值給 FormControl

      只有當(dāng)兩個(gè)驗(yàn)證器都合法時(shí),FormControl 才是合法的

      Validators.compose([Validators.required, textValidator]) // 不用compose   [Validators.required, textValidator] // 保留 compose 是為了向以前歷史版本進(jìn)行兼容,不用 compose 也可實(shí)現(xiàn)
      登錄后復(fù)制

      動(dòng)態(tài)表單

      要實(shí)現(xiàn) Angular 動(dòng)態(tài)表單,主要使用 formArray 方法,formArray 生成的實(shí)例是一個(gè)數(shù)組,在這個(gè)數(shù)組中可以動(dòng)態(tài)的放入 formGroupformControl,這樣便形成了動(dòng)態(tài)表單。

      export class ReativeFormsComponent implements OnInit {   ngOnInit() {     this.addContact()   }   //動(dòng)態(tài)表單   personMess: FormGroup = new FormGroup({     //生成動(dòng)態(tài)表單數(shù)組     contacts: new FormArray([])    })   //獲取數(shù)組對(duì)象   get contacts(){     return this.personMess.get('contacts') as FormArray   }   //增加一個(gè)表單組   addContact(){     let myContact = new FormGroup({       name: new FormControl(),       phone: new FormControl()     })     this.contacts.push(myContact)   }    //刪除一個(gè)表單組   deleteContact(i:number){     this.contacts.removeAt(i)   }   //提交表單   OnSubmit() {     console.log(this.personMess.value)   } }
      登錄后復(fù)制

      <form [formGroup]="personMess" (submit)="OnSubmit()">   <div formArrayName="contacts">     <!-- 注意:這里遍歷的時(shí)contacts.controls -->     <div *ngFor="let contact of contacts.controls;let i =index" [formGroupName]="i">       <input type="text" formControlName="name">       <input type="text" formControlName="phone">       <button (click)="deleteContact(i)">刪除信息</button>     </div>   </div>   <button (click)="addContact()">添加信息</button><br>   <input type="submit"> </form>
      登錄后復(fù)制

      Angular CDK

      CDK 是 Component Dev kit 的簡(jiǎn)稱(chēng),是 Angular Material 團(tuán)隊(duì)在開(kāi)發(fā) Library 時(shí)發(fā)現(xiàn)組件有很多相似的地方,最后進(jìn)行了抽取,提煉出了公共的邏輯,這部分即是 CDK

      官方用了一個(gè)很形象的比喻:如果組件庫(kù)是火箭飛船,那么 CDK 就是發(fā)動(dòng)機(jī)零件盒
      深入了解Angular(新手入門(mén)指南)

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)