日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Angular 從入坑到挖坑 - 組件食用指南

 小樣樣樣樣樣樣 2020-08-03

一、Overview

angular 入坑記錄的筆記第二篇,介紹組件中的相關(guān)概念,以及如何在 angular 中通過使用組件來完成系統(tǒng)功能的實(shí)現(xiàn)

對應(yīng)官方文檔地址:



配套代碼地址:angular-practice/src/components-guide

二、Contents

  1. Angular 從入坑到棄坑 - Angular 使用入門

  2. Angular 從入坑到挖坑 - 組件食用指南

三、Knowledge Graph

思維導(dǎo)圖

四、Step by Step

4.1、組件與模板

4.1.1、組件的基礎(chǔ)概念

組件包含了一組特定的功能,每個(gè)組件的功能都單一且獨(dú)立,可以進(jìn)行重復(fù)使用;組件可以通過 angular cli 進(jìn)行創(chuàng)建,生成的組件位于工作空間的 src/app/ 路徑下面

## 創(chuàng)建一個(gè) product-list 組件
ng g component product-list

當(dāng)需要將組件放置在某個(gè)指定的目錄下時(shí),可以直接在 ng g 命令中添加路徑

## 將 hero 組件生成到 components 路徑下
ng g component components/hero

創(chuàng)建新組件

angular 應(yīng)用就是通過一個(gè)個(gè)的組件所構(gòu)成的組件樹,一個(gè)組件包含了如下的四個(gè)部分

  • product-list.component.ts:組件類,用來處理數(shù)據(jù)和功能,為視圖呈現(xiàn)提供支持

  • product-list.component.html:組件對應(yīng)的頁面 HTML 模板,用來呈現(xiàn)組件的功能

  • product-list.component.scss:只針對當(dāng)前組件的樣式

  • product-list.component.spec.ts:當(dāng)前組件的單元測試文件(非必須)

當(dāng)通過命令行創(chuàng)建一個(gè)新的組件之后,會(huì)自動(dòng)將新創(chuàng)建的組件注冊到應(yīng)用的根模塊(app.module.ts)中

注冊組件

在組件類中,通過使用 @Component 裝飾器 [1] 用來將類聲明為組件類,并為這個(gè)組件類配置一些元數(shù)據(jù) [2],以決定該組件在運(yùn)行期間該如何處理、實(shí)例化和使用

裝飾器中存在三個(gè)基礎(chǔ)的配置參數(shù),用來完成組件與視圖之間的關(guān)聯(lián)

  • selector:選擇器,當(dāng)我們在頁面上添加了這個(gè)選擇器指定的標(biāo)簽(<app-product-list></app-product-list>)后,就會(huì)在當(dāng)前使用位置上創(chuàng)建并插入這個(gè)組件的一個(gè)實(shí)例

  • templateUrl:該組件所對應(yīng)的 HTML 模板文件地址

  • styleUrls:該組件視圖所特有的 css 樣式文件地址

組件的聲明

當(dāng)需要使用這個(gè)組件時(shí),直接在頁面上添加選擇器對應(yīng)的標(biāo)簽就可以了

組件的使用

4.1.2、模板綁定語法

在 angular 應(yīng)用中,組件扮演著控制器或是視圖模型的作用,在創(chuàng)建組件時(shí)會(huì)關(guān)聯(lián)一個(gè) html 文件,這個(gè) html 文件則是一個(gè)基礎(chǔ)的 angular 模板文件

在這個(gè)模板文件中,可以通過 angular 內(nèi)置的模板語法與 html 元素進(jìn)行結(jié)合,從而告訴 angular 如何根據(jù)我們的應(yīng)用邏輯和數(shù)據(jù)來渲染頁面

4.1.2.1、插值表達(dá)式

插值表達(dá)式可以將組件中的屬性值或者是模板上的數(shù)據(jù)通過模板表達(dá)式運(yùn)算符進(jìn)行計(jì)算,最終將值渲染到視圖頁面上

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

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.scss']
})

export class ProductListComponent implements OnInit {

  public title = '我是 title 屬性值';

  constructor() { }

  ngOnInit(): void {
  }
}
<p>title:{{title}}</p>

<p>1+2+3+4+5={{1+2+3+4+5}}</p>

插值表達(dá)式

模板表達(dá)式的變量來源

  • 模板本身的變量

  • 指令的上下文變量

  • 組件的成員信息(屬性 or 方法)

在使用模板表達(dá)式時(shí),如果變量名在多個(gè)來源中都存在的話,則模板變量是最優(yōu)先的,其次是指令的上下文變量,最后是組件的成員

在使用模板表達(dá)式時(shí)應(yīng)該遵循如下的原則

  • 簡單:正常情況下,應(yīng)該將業(yè)務(wù)邏輯或是數(shù)據(jù)運(yùn)算放到組件中,模板表達(dá)式只作為屬性或方法的調(diào)用

  • 快速執(zhí)行:模板表達(dá)式得出的數(shù)據(jù)應(yīng)該快速結(jié)束,否則就會(huì)對于用戶體驗(yàn)造成影響

  • 沒有可見的副作用:模板表達(dá)式只作為數(shù)據(jù)的展示,不應(yīng)該改變?nèi)魏蔚臄?shù)據(jù);應(yīng)該構(gòu)建出冪等的表達(dá)式,除非依賴的值發(fā)生變化,否則多次調(diào)用時(shí),應(yīng)該返回相同的數(shù)據(jù)信息

4.1.2.2、模板綁定語法

通過數(shù)據(jù)綁定機(jī)制,將數(shù)據(jù)源與視圖進(jìn)行綁定,從而實(shí)現(xiàn)源數(shù)據(jù)與用戶呈現(xiàn)的一致性

  • 從數(shù)據(jù)源到視圖:插值、組件中的屬性、dom 元素的 property [3]、css 樣式、css 類

  • 從視圖到數(shù)據(jù)源:事件

  • 視圖與數(shù)據(jù)源之間的雙向綁定:數(shù)據(jù)對象

分類語法
單向
從數(shù)據(jù)源到視圖
1、插值表達(dá)式:{{expression}}
2、使用 [] 進(jìn)行綁定:<a [href]='expression'></a>
3、使用 bind 進(jìn)行綁定:<a bind-href='expression'></a>
單向
從視圖到數(shù)據(jù)源
1、使用 () 進(jìn)行綁定:<a (click)='statement'></a>
2、使用 on 進(jìn)行綁定:<a on-click='statement'></a>
雙向
視圖到數(shù)據(jù)源;數(shù)據(jù)源到視圖
1、使用 [()] 進(jìn)行綁定:<input type="text" [(ngModel)]="product.Name">
2、使用 bindon 進(jìn)行綁定:<input type="text" bindon-ngModel="product.Name">
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.scss']
})

export class ProductListComponent implements OnInit {

  public title = '我是 title 屬性值';
    
  public styleProperty = '<b>我是包含 html 標(biāo)簽的屬性</b>';

  public fontColor = 'red';

  public url = 'https://';

  public name: string;

  constructor() { }

  ngOnInit(): void {
  }

  getUser() {
    alert('111111111');
  }
}
<h3>2.1、從數(shù)據(jù)源到視圖</h3>

<p>
  <a href='{{url}}'>使用插值表達(dá)式進(jìn)行綁定</a>
</p>
<p>
  <a [href]='url' [style.color]='fontColor'>使用 [] 進(jìn)行綁定</a>
</p>
<p>
  <a bind-href='url'>使用 bind 進(jìn)行綁定</a>
</p>
<p>
  <span [innerHtml]="styleProperty"></span>
</p>

<h3>2.2、從視圖到數(shù)據(jù)源</h3>

<p>
  <button (click)="getUser()">使用 () 進(jìn)行綁定</button>
</p>
<p>
  <button on-click="getUser()">使用 on 進(jìn)行綁定</button>
</p>

<h3>2.3、數(shù)據(jù)雙向綁定 --- 需要在 AppModule 中添加對于 FormsModule 的引用</h3>

<p>
  <input type="text" id="userName" [(ngModel)]="name">
</p>
<p>
  <input type="text" bindon-ngModel="name">
</p>

模板綁定語法

4.1.3、數(shù)據(jù)綁定
  • 單向數(shù)據(jù)綁定

    <p>{{title}}</p>
  • 雙向數(shù)據(jù)綁定

    <input type="text" id="userName" [(ngModel)]="name">
    
    <!-- 
      當(dāng)沒有 NgModel 時(shí),雙向數(shù)據(jù)綁定等同于下面的寫法
     -->
    <input type="text" id="userName" [value]="name" (input)="name=$event.target.value">
4.1.4、屬性、樣式綁定
  • dom 元素的 property 綁定

    <img [src]="productImageUrl">
    
    <img bind-src="productImageUrl">
  • html 標(biāo)簽的 attribute 綁定

    attribute 綁定的語法類似于 property 綁定,由前綴 attr、點(diǎn)( . )和 attribute 名稱組成

    attribute 綁定的主要用例之一是設(shè)置 ARIA attribute(給殘障人士提供便利)

    <button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
  • style 內(nèi)聯(lián)樣式綁定

    // 1、[style.width]="width" :string | undefined | null
    public width = "100px";
    
    //2、[style.width.px]="width":number | undefined | null
    public width = "20";
    
    // 3、[style]="styleExpr":string
    public styleExpr = "width: 100px; color:red";
    
    // 4、[style]="styleExpr":{key:value}
    public styleExpr = {width: '100px', height: '100px'};
    
    // 5、[style]="styleExpr":array
    public styleExpr = ["width", "100px"];
  • class 屬性綁定

    // 1、[class.foo]="hasFoo":bool | undefined | null
    public hasFoo = true;
    
    // 2、[class]="classExpr":string
    public classExpr = "my-class1 my-class2";
    
    // 3、[class]="classExpr":{key:value}
    public classExpr= {my-class1:  true, my-class2: true};
    
    // 4、[class]="classExpr":array
    public classExpr= ["my-class1", "my-class2"];
4.1.5、事件綁定

在事件綁定中,可以通過 $event 參數(shù)獲取到 dom 事件對象的屬性從而獲取到模板信息

<input type="text" (keyup)="getMsg($event)">
<p>輸入的值:{{msg}}</p>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.scss']
})

export class ProductListComponent implements OnInit {

  public msg: string;
  
  constructor() { }

  ngOnInit(): void {
  }

  getMsg(event: KeyboardEvent) {
    console.log(event);
    this.msg = (event.target as HTMLInputElement).value;
  }
}

綁定事件

通過使用 $event 作為方法的參數(shù)會(huì)將許多用不到的模板信息傳遞到組件中,導(dǎo)致我們在僅僅是為了獲取數(shù)據(jù)的前提下,卻需要對于頁面元素十分了解,違背了模板(用戶所能看到的)與組件(應(yīng)用如何去處理用戶數(shù)據(jù))之間的關(guān)注點(diǎn)分類的原則。因此,這里應(yīng)該使用模板引用變量的方式獲取數(shù)據(jù)信息。

模板引用變量是對模板中 DOM 元素的引用,提供了從模塊中直接訪問元素的能力。

<input type="text" #refMsgInput (keyup)="getRefMsg(refMsgInput.value)">
<p>通過模板引入變量的方式獲取到輸入的值:{{refMsg}}</p>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.scss']
})

export class ProductListComponent implements OnInit {

  public refMsg: string;

  constructor() { }

  ngOnInit(): void {
  }

  getRefMes(msg: string) {
    this.refMsg = msg;
  }
}

模板引用變量的作用域是整個(gè)模板,因此要確保一個(gè)模板中的引用變量名稱是唯一的,同時(shí),在聲明引用變量時(shí),也可以使用 ref- 代替 #

<input type="text" ref-refMsgInput (keyup)="getRefMsg(refMsgInput.value)">
<p>通過模板引入變量的方式獲取到輸入的值:{{refMsg}}</p>

4.2、指令

4.2.1、屬性型指令

屬性型指令被應(yīng)用在視圖 dom 元素上,用來改變 dom 元素的外觀或行為

  • NgClass:用來設(shè)置元素的多個(gè) css 類屬性,如果只設(shè)置一個(gè) css 類,應(yīng)該使用模板綁定語法中 class 類綁定

    <p [ngClass]="inlineStyle">NgClass 屬性指令</p>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-product-list',
      templateUrl: './product-list.component.html',
      styleUrls: ['./product-list.component.scss']
    })
    
    export class ProductListComponent implements OnInit {
    
      public inlineStyle: {};
    
      constructor() { }
    
      ngOnInit(): void {
        this.setInlineStyle();
      }
    
      setInlineStyle() {
        this.inlineStyle = {
          'text-red': true,
          'bg-blue': false,
        };
      }
    }

    這里的 text-red、bg-blue 都是 css 類名,如果想要在指定的元素上添加該類,則 css 類名對應(yīng)的值為 true,反之則為 false

  • NgStyle:用來設(shè)置元素的多個(gè)內(nèi)聯(lián)樣式,如果只設(shè)置一個(gè)內(nèi)聯(lián)樣式,應(yīng)該使用模板綁定語法中的樣式綁定

    <p [ngStyle]="currentStyles">NgStyle 屬性指令</p>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-product-list',
      templateUrl: './product-list.component.html',
      styleUrls: ['./product-list.component.scss']
    })
    
    export class ProductListComponent implements OnInit {
    
      public currentStyles: {};
    
      constructor() { }
    
      ngOnInit(): void {
        this.setCurrentStyles();
      }
    
      setCurrentStyles() {
        this.currentStyles = {
          'font-style': 'italic',
          'font-weight': 'bold',
          'font-size': '24px'
        };
      }
    }

    通過在組件的屬性中設(shè)置多個(gè)內(nèi)聯(lián)樣式對象的形式,完成對于頁面元素樣式的批量設(shè)置

  • NgModel:雙向數(shù)據(jù)綁定

    <input type="text" id="userName" [(ngModel)]="name">

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

4.2.2、結(jié)構(gòu)型指令

結(jié)構(gòu)型指令用來操作 dom 樹,通過進(jìn)行一些的邏輯判斷,從而完成對于頁面布局的修改

  • NgIf:根據(jù)表達(dá)式的值(true or false)來創(chuàng)建或者銷毀 dom 元素

    <p *ngIf="expr">NgIf 結(jié)構(gòu)型指令</p>

    當(dāng) expr 屬性為 true 時(shí),這個(gè)元素則會(huì)顯示在頁面上,當(dāng)屬性值為 false 時(shí),則不顯示該元素

    ngIf 指令并不是通過使用 css 樣式來隱藏元素的,當(dāng)值為 false 時(shí),則這些元素會(huì)從 dom 中被銷毀,并且所有監(jiān)聽該 dom 元素的事件會(huì)被取消,當(dāng)重新顯示該元素時(shí),會(huì)重新執(zhí)行初始化的過程

    與銷毀元素不同,對于隱藏的元素來說,所有的元素監(jiān)聽事件還會(huì)執(zhí)行監(jiān)聽的,再次顯示時(shí)不用重新進(jìn)行初始化過程

  • NgFor:通過定義單條數(shù)據(jù)的顯示格式,angular 以此為模板,循環(huán)渲染出所有的數(shù)據(jù)

    <p *ngFor="let item of products; let i = index">{{i+1}} - {{item.name}} --- {{item.price}}</p>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-product-list',
      templateUrl: './product-list.component.html',
      styleUrls: ['./product-list.component.scss']
    })
    
    export class ProductListComponent implements OnInit {
    
      public products = [{
        'name': 'lalala',
        'price': '$200'
      }, {
        'name': 'hehehe',
        'price': '$400'
      }, {
        'name': 'wuwuwu',
        'price': '$120'
      }, {
        'name': 'xixi',
        'price': '$570'
      }];
    
      constructor() { }
    
      ngOnInit(): void {
      }
    }

    NgFor 指令上下文中的 index 屬性在每次迭代中,會(huì)獲取到條數(shù)據(jù)的索引值

    當(dāng)渲染的數(shù)據(jù)發(fā)生改變時(shí) [4],會(huì)導(dǎo)致 dom 元素的重新渲染,此時(shí)可以采用 trackBy 的方式,通過在組件中添加一個(gè)方法,指定循環(huán)需要跟蹤的屬性值,此時(shí)當(dāng)渲染的數(shù)據(jù)發(fā)生改變時(shí),只會(huì)重新渲染變更了指定的屬性值的數(shù)據(jù)

    <p>不使用 trackBy 跟蹤屬性</p>
    <div>
      <p *ngFor="let item of products; let i = index;">
        {{i+1}} - {{item.name}} --- {{item.price}}
      </p>
    </div>
    <p>使用 trackBy 跟蹤屬性</p>
    <div>
      <p *ngFor="let item of products; let i = index; trackBy: trackByIndex">
        {{i+1}} - {{item.name}} --- {{item.price}}
      </p>
    </div>
    <button (click)="addProduct()">新增</button>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-product-list',
      templateUrl: './product-list.component.html',
      styleUrls: ['./product-list.component.scss']
    })
    
    export class ProductListComponent implements OnInit {
    
      public products = [{
        'name': 'lalala',
        'price': '$200'
      }, {
        'name': 'hehehe',
        'price': '$400'
      }, {
        'name': 'wuwuwu',
        'price': '$120'
      }, {
        'name': 'xixi',
        'price': '$570'
      }];
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
      trackByIndex(index: number, item: any): string {
        return item.price;
      }
    
      addProduct() {
        this.products = [{
          'name': 'lalala',
          'price': '$200'
        }, {
          'name': 'hehehe',
          'price': '$400'
        }, {
          'name': 'wuwuwu',
          'price': '$120'
        }, {
          'name': 'xixi',
          'price': '$570'
        }, {
          'name': 'lululu',
          'price': '$' + (Math.random() * 100).toFixed()
        }];
      }
    }

    trackBy 監(jiān)聽變化

  • NgSwitch:根據(jù)條件切換,從候選的幾個(gè)元素中選擇匹配的,放到 dom 元素中

    <p>
      請選擇配置
      <select [(ngModel)]="config">
        <option value="">請選擇</option>
        <option value="r7-3700x">AMD Ryzen 7 3700X</option>
        <option value="i5-9400f">Intel i5 9400F</option>
        <option value="i5-9600kf">Intel i5 9600KF</option>
      </select>
    </p>
    <p> 配置描述 </p>
    <div [ngSwitch]="config">
      <p *ngSwitchCase="'r7-3700x'">
        一個(gè)能打得都木的~~~
      </p>
      <p *ngSwitchCase="'i5-9400f'">
        擠牙膏的。。。
      </p>
      <p *ngSwitchCase="'i5-9600kf'">
        別看了,我不是開封菜。。。
      </p>
      <p *ngSwitchDefault>
        你選一個(gè)啊~~~
      </p>
    </div>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-product-list',
      templateUrl: './product-list.component.html',
      styleUrls: ['./product-list.component.scss']
    })
    
    export class ProductListComponent implements OnInit {
    
      public config = '';
    
      constructor() { }
    
      ngOnInit(): void {
      }
    }

    NgSwitch

    NgSwitch 本身是一個(gè)屬性型指令,它不會(huì)直接操作 dom 元素,而是通過它所控制的兩個(gè)結(jié)構(gòu)型指令(NgSwitchCase、ngSwitchDefault)來操作 dom 元素

4.3、管道

在使用模板表達(dá)式綁定數(shù)據(jù)時(shí),可以使用管道對于表達(dá)式的結(jié)果進(jìn)行轉(zhuǎn)換

管道是一種簡單的函數(shù),它們接受輸入值并返回轉(zhuǎn)換后的值。通過在模板表達(dá)式中使用管道運(yùn)算符(|)則可以完成相應(yīng)的結(jié)果轉(zhuǎn)換

4.3.1、模板表達(dá)式中的特殊運(yùn)算符

angular 模板表達(dá)式是 javascript 的子集,相對于常見的 javascript 運(yùn)算符,添加了三個(gè)特殊的運(yùn)算符

  • 管道運(yùn)算符

    管道是一種特殊的函數(shù),可以把運(yùn)算符(|)左邊的數(shù)據(jù)轉(zhuǎn)換成期望呈現(xiàn)給視圖的數(shù)據(jù)格式,例如,將時(shí)間進(jìn)行格式化、將數(shù)據(jù)轉(zhuǎn)換成 json 字符串的形式等等

    可以針對一個(gè)數(shù)據(jù)使用多個(gè)管道進(jìn)行串聯(lián),并且管道運(yùn)算符的優(yōu)先級(jí)比三元運(yùn)算符( ?: )高

    <h3>5.1、管道運(yùn)算符</h3>
    <div>
      <p>產(chǎn)品信息 json 字符串</p>
      {{products | json}}
    </div>

    管道運(yùn)算符的使用

  • 安全導(dǎo)航運(yùn)算符

    在視圖中使用的屬性值為 null or undefined 時(shí),javascript 和 angular 會(huì)引發(fā)空指針異常并中斷視圖的渲染過程, 從而視圖會(huì)渲染失敗,而使用了安全導(dǎo)航運(yùn)算符(?)后,視圖依然會(huì)渲染,只是顯示的值為空白

    <h3>5.2、安全導(dǎo)航運(yùn)算符</h3>
    <p>第五個(gè)專案的名稱為:{{products[5].name}}</p>

    視圖渲染失敗

    <p>第五個(gè)專案的名稱為:{{products[5]?.name}}</p>

    視圖渲染成功

  • 非空斷言運(yùn)算符

    在 tsconfig.json 中啟用 strictNullChecks 屬性,typescript 將會(huì)強(qiáng)制開啟嚴(yán)格的空值檢查,在這種模式下,所有定義了類型的屬性是不允許賦值為 null 的,當(dāng)將屬性賦值為 null,則會(huì)編譯報(bào)錯(cuò)

    嚴(yán)格空值檢查

    非空斷言運(yùn)算符用來告訴編譯器對特定的屬性不做嚴(yán)格的空值校驗(yàn),當(dāng)屬性值為 null or undefined 時(shí),不拋錯(cuò)誤。在下面的代碼中,在判斷 obj 存在后,就不再針對 obj.name 進(jìn)行校驗(yàn)

    import { Component, OnInit } from '@angular/core';
    
    interface Person {
        name: string;
        age: number;
      }
    
      @Component({
        selector: 'app-product-list',
        templateUrl: './product-list.component.html',
        styleUrls: ['./product-list.component.scss']
      })
    
      export class ProductListComponent implements OnInit {
    
        public obj: Person;     
          
        constructor() {
        }
          
        ngOnInit(): void {
        }
    
      }
    <p *ngIf="obj">
      <span>{{obj!.name}}</span>
    </p>

    非空斷言運(yùn)算符不會(huì)防止出現(xiàn) null 或 undefined,只是不提示

4.3.2、常用的管道函數(shù)
  • 純管道

    只有在它檢測到輸入值發(fā)生了純變更時(shí)才會(huì)執(zhí)行,但是會(huì)忽略對象內(nèi)部的變更

    純變更是指對原始類型值(String、Number、Boolean、Symbol)的更改, 或者對對象引用(Date、Array、Function、Object)的更改

  • 非純管道

    每個(gè)組件的變更周期都會(huì)執(zhí)行

管道作用
JsonPipe將一個(gè)值轉(zhuǎn)換成 json 字符串
DatePipe根據(jù)區(qū)域設(shè)置規(guī)則格式化日期值
UpperCasePipe把文本轉(zhuǎn)換成全大寫形式
LowerCasePipe把文本轉(zhuǎn)換成全小寫形式
<h3>6.1、json 管道</h3>
<p>{{products | json}}</p>

<h3>6.2、date 管道</h3>
<p>現(xiàn)在時(shí)間:{{date | date:'yyyy-MM-dd HH:mm:ss'}}</p>

<h3>6.3、upper 管道</h3>
<p>轉(zhuǎn)換成全大寫:{{url | uppercase}}</p>

<h3>6.4、lower 管道</h3>
<p>轉(zhuǎn)換成全小寫:{{url | lowercase}}</p>

管道函數(shù)

4.4、組件之間的通信

4.4.1、輸入屬性與輸出屬性

輸入屬性(@Input)和輸出屬性(@Output)用來在父子組件或指令中進(jìn)行共享數(shù)據(jù)。@Input 用來獲取數(shù)據(jù),@Output 用來向外發(fā)送數(shù)據(jù)

4.4.2、子組件獲取父組件信息
  • 在父組件中,添加對于子組件的引用,并將需要傳遞的數(shù)據(jù) or 方法綁定到子組件上

    傳遞數(shù)據(jù)直接將父組件中的屬性值賦值給綁定在子組件上的屬性就可以了

    傳遞方法時(shí),綁定在子組件上的屬性是父組件方法的名稱,此處不能加 () ,否則就會(huì)直接執(zhí)行該父組件的方法

    在傳遞數(shù)據(jù)給子組件時(shí),也可以通過 this 來指代父組件,從而將整個(gè)父組件作為數(shù)據(jù)綁定子組件上

    <h2>父組件內(nèi)容:</h2>
    
    <p>
      <label for="title">標(biāo)題:</label>
      <input id="title" type="text" [(ngModel)]="title">
    </p>
    
    <hr>
    
    <h2>子組件內(nèi)容:</h2>
    
    <!--
      將父組件的數(shù)據(jù)綁定到子組件上
     -->
    <app-child-component [parentTitle]="title" [parentGetMsg]='getMsg'></app-child-component>

    父組件傳遞數(shù)據(jù)給子組件

  • 在子組件中引入 Inupt,同時(shí)使用 @Input 裝飾器來接收父組件傳遞的數(shù)據(jù)

    // 引入 Input 接口
    import { Component, OnInit, Input } from '@angular/core';
    
    @Component({
      selector: 'app-child-component',
      templateUrl: './child-component.component.html',
      styleUrls: ['./child-component.component.scss']
    })
    export class ChildComponentComponent implements OnInit {
    
      // 獲取父組件的數(shù)據(jù)
      @Input() parentGetMsg: any;
    
      // 使用 setter 對父組件的數(shù)據(jù)進(jìn)行深加工
      private _title: string;
      @Input()
      set parentTitle(title: string) {
        this._title = (title && title.trim()) || '父組件的 title 屬性值為空';
      }
      get parentTitle(): string {
        return this._title;
      }
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
      runParentFunc() {
        this.parentGetMsg();
      }
    }
    <p>父組件的 title 屬性值:{{parentTitle}}</p>
    <p>
      <button (click)="runParentFunc()">調(diào)用父組件的方法</button>
    </p>

    對于使用 @Input 裝飾器獲取到的父組件數(shù)據(jù),可以通過輸入屬性中的 setter 方法中進(jìn)行重新賦值

    子組件獲取父組件數(shù)據(jù)

4.4.3、父組件獲取子組件信息
  • 使用 @ViewChild 裝飾器獲取

    在子組件上定義一個(gè)模板引用變量

    <h2>父組件內(nèi)容:</h2>
    
    <h3>1、使用 @ViewChild 裝飾器獲取子組件數(shù)據(jù)</h3>
    
    <p>
      <button (click)="getChildMsg()">獲取子組件的 msg 數(shù)據(jù)</button>
    </p>
    
    <p>
      <button (click)="runChildFunc()">調(diào)用子組件的方法</button>
    </p>
    
    <hr>
    
    <h2>子組件內(nèi)容:</h2>
    
    <!--
      在子組件上定義一個(gè)模板引用變量
     -->
    <app-child-component #childComponent></app-child-component>

    在父組件中添加對于 ViewChild 的引用,然后使用 @ViewChild 裝飾器來接收子組件的 dom 信息,從而獲取到子組件的數(shù)據(jù)或方法

    // 引入 ViewChild
    import { Component, OnInit, ViewChild } from '@angular/core';
    
    @Component({
      selector: 'app-parent-component',
      templateUrl: './parent-component.component.html',
      styleUrls: ['./parent-component.component.scss']
    })
    export class ParentComponentComponent implements OnInit {
    
      // 通過 @ViewChild 裝飾器來接收字組件的 dom 信息
      @ViewChild('childComponent') child: any;
    
      constructor() {
      }
    
      ngOnInit(): void {
      }
    
      getMsg() {
        alert('我是父組件的 getMsg 方法');
      }
    
      getChildMsg() {
        alert(this.child.msg);
      }
    }

    通過 @ViewChild 裝飾器獲取子組件數(shù)據(jù)

  • 使用 @Output 裝飾器配合 EventEmitter 實(shí)現(xiàn)

    在子組件中引入 Output 和 EventEmitter,通過 @Output 裝飾器定義一個(gè)事件觸發(fā)器,然后就可以通過這個(gè)事件觸發(fā)器的 emit 方法進(jìn)行事件廣播

    // 引入 Output、EventEmitter
    import { Component, OnInit, Output, EventEmitter } from '@angular/core';
    
    @Component({
      selector: 'app-child-component',
      templateUrl: './child-component.component.html',
      styleUrls: ['./child-component.component.scss']
    })
    export class ChildComponentComponent implements OnInit {
    
      public msg = 'child title';
    
      // 定義一個(gè)事件觸發(fā)器
      @Output() childEmitter = new EventEmitter<string>();
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
      runParentFunc() {
        this.parentGetMsg();
      }
    
      sendMsg() {
        this.childEmitter.emit(this.msg);
      }
    }

    當(dāng)子組件進(jìn)行事件廣播時(shí),就可以通過在子組件上使用事件綁定的方式綁定到一個(gè)父組件事件,通過 $event 獲取到子組件傳遞的數(shù)據(jù)值

    <h2>父組件內(nèi)容:</h2>
    
    <h3>2、使用 @Output 裝飾器配合 EventEmitter 獲取子組件數(shù)據(jù)</h3>
    
    <p>{{childMsg}}</p>
    
    <hr>
    
    <h2>子組件內(nèi)容:</h2>
    
    <!--
      將子組件的事件廣播綁定到父組件事件上
     -->
    <app-child-component (childEmitter)='childEmitMsg($event)'></app-child-component>
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-parent-component',
      templateUrl: './parent-component.component.html',
      styleUrls: ['./parent-component.component.scss']
    })
    export class ParentComponentComponent implements OnInit {
    
      public childMsg: string;
    
      constructor() {
      }
    
      ngOnInit(): void {
      }
    
      childEmitMsg(event) {
        this.childMsg = event;
      }
    }

    使用 @Output 裝飾器獲取子組件數(shù)據(jù)

4.4.4、非父子組件之間的通信

不管組件之間是否具有關(guān)聯(lián)關(guān)系,都可以通過共享一個(gè)服務(wù)的方式來進(jìn)行數(shù)據(jù)交互,也可以將需要進(jìn)行共享的數(shù)據(jù)存儲(chǔ)到一些存儲(chǔ)介質(zhì)中,通過直接讀取這個(gè)存儲(chǔ)介質(zhì)中的數(shù)據(jù)進(jìn)行通信

  • 創(chuàng)建一個(gè)服務(wù),并添加到模塊中

    ## 在 services/storage 路徑下創(chuàng)建一個(gè) storage 服務(wù)
    ng g service services/storage/storage
    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { ProductListComponent } from './product-list/product-list.component';
    import { FormsModule } from '@angular/forms';
    import { ParentComponentComponent } from './parent-component/parent-component.component';
    import { ChildComponentComponent } from './child-component/child-component.component';
    
    // 引入自定義的服務(wù)
    import { StorageService } from './services/storage/storage.service';
    
    @NgModule({
      declarations: [
        AppComponent,
        ProductListComponent,
        ParentComponentComponent,
        ChildComponentComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        FormsModule
      ],
      // 配置自定義的服務(wù)
      providers: [StorageService],
      bootstrap: [AppComponent]
    })
    
    export class AppModule { }

    創(chuàng)建一個(gè)服務(wù)

  • 在組件中使用服務(wù)

    在需要使用的組件中引入服務(wù),然后在組件的構(gòu)造函數(shù)中通過依賴注入的方式注入這個(gè)服務(wù),就可以在組件中完成對于這個(gè)服務(wù)的使用

    在父組件中對數(shù)據(jù)進(jìn)行賦值,然后調(diào)用服務(wù)的方法改變數(shù)據(jù)信息

    import { Component, OnInit } from '@angular/core';
    
    // 引入服務(wù)
    import { StorageService } from '../services/storage/storage.service';
    
    @Component({
      selector: 'app-parent-component',
      templateUrl: './parent-component.component.html',
      styleUrls: ['./parent-component.component.scss']
    })
    export class ParentComponentComponent implements OnInit {
    
      public msg = 'this is a service default value writen in parent component';
    
      constructor(private storage: StorageService) {
        this.storage.setMsg(this.msg);
      }
    
      ngOnInit(): void {
      }
    
      submit() {
        this.storage.setMsg(this.msg);
      }
    }
    <h2>父組件內(nèi)容:</h2>
    
    <h3>3、通過服務(wù)在屬性中共享數(shù)據(jù)</h3>
    
    <p>
      修改服務(wù)中的數(shù)據(jù)值
      <input type="text" [(ngModel)]="msg">
      <button (click)="submit()">提交</button>
    </p>
    
    <p>服務(wù)中的數(shù)據(jù):{{msg}}</p>
    
    <hr>
    
    <h2>子組件內(nèi)容:</h2>
    
    <app-child-component></app-child-component>

    在子組件中引入服務(wù),從而同步獲取到父組件修改后的服務(wù)中的數(shù)據(jù)信息

    import { Component, OnInit } from '@angular/core';
    
    // 引入服務(wù)
    import { StorageService } from '../services/storage/storage.service';
    
    @Component({
      selector: 'app-child-component',
      templateUrl: './child-component.component.html',
      styleUrls: ['./child-component.component.scss']
    })
    export class ChildComponentComponent implements OnInit {
    
      public storageMsg: string;
    
      constructor(private storage: StorageService) {
      }
    
      ngOnInit(): void {
      }
    
      getServiceMsg() {
        this.storageMsg = this.storage.getMsg();
      }
    }
    <button (click)="getServiceMsg()">獲取服務(wù)中的數(shù)據(jù)值</button>
    <p>
      服務(wù)中 msg 屬性值:{{storageMsg}}
    </p>

    通過服務(wù)在組件間共享數(shù)據(jù)

五、組件的生命周期鉤子函數(shù)

當(dāng) angular 在創(chuàng)建、更新、銷毀組件時(shí)都會(huì)觸發(fā)組件的生命周期鉤子函數(shù),通過在組件中實(shí)現(xiàn)這些生命周期函數(shù),從而介入到這些關(guān)鍵時(shí)刻

鉤子函數(shù)觸發(fā)時(shí)機(jī)
ngOnChanges被綁定的輸入屬性值發(fā)生變化時(shí)觸發(fā),會(huì)調(diào)用多次;如果沒有使用到父子組件傳值,則不會(huì)觸發(fā)
ngOnInit初始化組件時(shí)會(huì)調(diào)用一次,一般是用來在構(gòu)造函數(shù)之后執(zhí)行組件復(fù)雜的初始化邏輯
ngDoCheck只要數(shù)據(jù)發(fā)生改變就會(huì)被調(diào)用
ngAfterContentInit組件內(nèi)容渲染完成后調(diào)用一次
ngAfterContentChecked只要組件的內(nèi)容發(fā)生改變就會(huì)被調(diào)用
ngAfterViewInit視圖加載完成后觸發(fā)一次,一般用來對視圖的 dom 元素進(jìn)行操作
ngAfterViewChecked視圖發(fā)生變化時(shí)調(diào)用,在組件的生命周期中會(huì)調(diào)用多次
ngOnDestroy只在銷毀組件時(shí)調(diào)用一次,一般用來在組件銷毀前執(zhí)行某些操作

在組件加載過程中,會(huì)按照上面列出的鉤子函數(shù)順序,在組件的構(gòu)造函數(shù)執(zhí)行之后依次執(zhí)行,在頁面加載過程中會(huì)涉及綁定數(shù)據(jù)的操作,因此會(huì)再次出發(fā) ngDoCheck、ngAfterContentChecked、ngAfterViewChecked 這三個(gè)生命周期鉤子函數(shù)。后續(xù)只要頁面數(shù)據(jù)有發(fā)生改變,都會(huì)觸發(fā)這幾個(gè)事件

組件的生命周期鉤子函數(shù)


  1. 裝飾器是一種特殊類型的聲明,它能夠被附加到類聲明,方法, 訪問符,屬性或參數(shù)上,就像是 C# 中的特性 ??

  2. 元數(shù)據(jù)是用來描述數(shù)據(jù)的數(shù)據(jù)項(xiàng),例如這里的 selector 是為了描述 Component 這個(gè)數(shù)據(jù)信息資源中抽取出來用于說明其特征的一個(gè)結(jié)構(gòu)化的數(shù)據(jù) ??

  3. property 是 dom 元素默認(rèn)的基本屬性,在 dom 初始化時(shí)會(huì)被全部創(chuàng)建,而 attribute 是 html 標(biāo)簽上定義的屬性和值 =》DOM 中 Property 和 Attribute 的區(qū)別 ??

  4. 這里的數(shù)據(jù)改變指的是會(huì)將原來的數(shù)據(jù)對象重新銷毀然后重建的過程,因此像 push、unshift 這樣的方法即使不添加 trackBy 也不會(huì)重新渲染整個(gè) DOM,只會(huì)重新渲染改變的數(shù)據(jù) ??

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多