溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

angular10組件的示例分析

發(fā)布時(shí)間:2021-07-27 10:51:25 來源:億速云 閱讀:122 作者:小新 欄目:web開發(fā)

這篇文章主要介紹了angular10組件的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

組件構(gòu)成要素

  • html模板

  • typescript,定義行為

  • css組,可以引入多個(gè)css文件,因此可以在一個(gè)組件里面定義多個(gè)css文件

//從angular主模塊中引入Component(組件裝飾器或組件注解)
import { Component } from '@angular/core';

//裝飾器中以json的形式聲明元數(shù)據(jù)
@Component({
  //它指定了一個(gè)叫 <app-root> 的元素。 該元素是 index.html 文件里的一個(gè)占位符
  //為什么這個(gè)組件跟入口index建立了聯(lián)系呢?因?yàn)槿肟趍ain.ts中綁定了主模塊為appModule
  selector: 'app-root',   //在模板中找對(duì)應(yīng)的標(biāo)簽,找到后創(chuàng)建并插入該組件實(shí)例
  templateUrl: './app.component.html',  // html模板
  styleUrls: ['./app.component.css'],   // css樣式,可以引入多個(gè)css文件
  // 這個(gè)屬性(內(nèi)聯(lián)模板)和templateUrl(外聯(lián)模板)二選一,template后面可以直接跟html字符串
  // 注意在模板語法(反引號(hào))中是使用插值表達(dá)式,不能使用${}插入值
  template: `<h2>{{title}}</h2>`   
})
//組件控制器,寫邏輯代碼的地方
export class AppComponent {
  title = 'myAngular';
  //構(gòu)造函數(shù)可以用來進(jìn)行屬性的聲明和初始化語句
  //在angular里面有個(gè)特別重要的點(diǎn)要記住:只能通過構(gòu)造函數(shù)注入依賴
  constructor() {}
}

先決條件

  • 安裝 Angular CLI (npm install -g @angular/cli)

  • 建立一個(gè) Angular 項(xiàng)目 (ng new )

如果不滿足這兩個(gè)條件,請(qǐng)參考 搭建環(huán)境。

如何創(chuàng)建一個(gè)組件

使用 Angular CLI 創(chuàng)建一個(gè)組件

ng generate component <project-name> // 創(chuàng)建一個(gè)組件

ng g c <project-name> // 縮寫

常用的創(chuàng)建組件的一些其他選項(xiàng)

ng g c <project-name>  --skip-tests // 創(chuàng)建一個(gè)組件,且不用安裝測(cè)試文件

ng g c <project-name> --inline-style // 縮寫-s,內(nèi)聯(lián)樣式

ng g c <project-name> --inline-template // 縮寫-t,內(nèi)聯(lián)模板

ng g c <project-name> --module= <module-name> // 指定創(chuàng)建的組件在哪個(gè)模塊引用,在多個(gè)模塊的項(xiàng)目中會(huì)用到

除了通過angular cli自動(dòng)生成組件外,也可以手動(dòng)創(chuàng)建組件(不推薦),這里不介紹。

組件的生命周期(高階內(nèi)容,掌握ngOnInit、ngOnDestroy、ngOnChanges、ngAfterViewInit())

在工作中經(jīng)常能夠用到的生命周期就兩個(gè)(ngOninit和ngOnDestroy),其他的生命周期很少用到;但是如果能夠掌握組件的生命周期,對(duì)angular會(huì)掌握的得更加深刻。

生命周期含義

當(dāng) Angular 實(shí)例化組件類并渲染組件視圖及其子視圖時(shí),組件實(shí)例的生命周期就開始了。生命周期一直伴隨著變更檢測(cè),Angular 會(huì)檢查數(shù)據(jù)綁定屬性何時(shí)發(fā)生變化,并按需更新視圖和組件實(shí)例。當(dāng) Angular 銷毀組件實(shí)例并從 DOM 中移除它渲染的模板時(shí),生命周期就結(jié)束了。當(dāng) Angular 在執(zhí)行過程中創(chuàng)建、更新和銷毀實(shí)例時(shí),指令就有了類似的生命周期。

應(yīng)用:

你的應(yīng)用可以使用生命周期鉤子方法來觸發(fā)組件或指令生命周期中的關(guān)鍵事件,以初始化新實(shí)例,需要時(shí)啟動(dòng)變更檢測(cè),在變更檢測(cè)過程中響應(yīng)更新,并在刪除實(shí)例之前進(jìn)行清理。

如何實(shí)現(xiàn)生命周期事件

每個(gè)組件或指令都可以實(shí)現(xiàn)一個(gè)或多個(gè)生命周期鉤子,這些生命周期鉤子可以在適當(dāng)?shù)臅r(shí)候?qū)M件或指令實(shí)例進(jìn)行操作。

每個(gè)接口都有唯一的一個(gè)鉤子方法,它們的名字是由接口名再加上 ng 前綴構(gòu)成的。比如,OnInit 接口的鉤子方法叫做 ngOnInit()。如果你在組件或指令類中實(shí)現(xiàn)了這個(gè)方法,Angular 就會(huì)在首次檢查完組件或指令的輸入屬性后,緊接著調(diào)用它

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

@Component({
  selector: 'app-root',
  styleUrls: ['./app.component.css'],  
  template: `<h2>{{title}}</h2>`   
})
// 實(shí)現(xiàn)OnInit生命周期,可以實(shí)現(xiàn)多個(gè)生命周期
export class AppComponent implements OnInit{ 
  title = 'myAngular';
  constructor() {}
  ngOnInit(){
      console.log("Angular在首次檢查完組件的輸入屬性后,然后調(diào)用它,只調(diào)用一次")
  }
}

生命周期概覽

鉤子時(shí)機(jī)用途注意
ngOnChanges()當(dāng)被綁定的輸入屬性的值發(fā)生變化時(shí)調(diào)用,首次調(diào)用一定會(huì)發(fā)生在 ngOnInit() 之前當(dāng) Angular 設(shè)置或重新設(shè)置數(shù)據(jù)綁定的輸入屬性時(shí)響應(yīng)。 該方法接受當(dāng)前和上一屬性值的 SimpleChanges 對(duì)象這發(fā)生的非常頻繁,所以你在這里執(zhí)行的任何操作都會(huì)顯著影響性能。
ngOnInit()在第一輪 ngOnChanges() 完成之后調(diào)用,只調(diào)用一次。在 Angular 第一次顯示數(shù)據(jù)綁定和設(shè)置指令/組件的輸入屬性之后,初始化指令/組件。組件獲取初始數(shù)據(jù)的好地方很重要,只調(diào)用一次
ngDoCheck()緊跟在每次執(zhí)行變更檢測(cè)時(shí)的 ngOnChanges() 和 首次執(zhí)行變更檢測(cè)時(shí)的 ngOnInit() 后調(diào)用。檢測(cè),并在發(fā)生 Angular 無法或不愿意自己檢測(cè)的變化時(shí)作出反應(yīng)。它和ngOnChanges一樣發(fā)生的很頻繁
ngAfterContentInit()第一次 ngDoCheck() 之后調(diào)用,只調(diào)用一次。當(dāng) Angular 把外部內(nèi)容投影進(jìn)組件視圖或指令所在的視圖之后調(diào)用。只調(diào)用一次
ngAfterContentChecked()ngAfterContentInit() 和每次 ngDoCheck() 之后調(diào)用每當(dāng) Angular 檢查完被投影到組件或指令中的內(nèi)容之后調(diào)用。
ngAfterViewInit()第一次 ngAfterContentChecked() 之后調(diào)用,只調(diào)用一次。初始化完組件視圖及其子視圖之后調(diào)用。只調(diào)用一次
ngAfterViewChecked()ngAfterViewInit() 和每次 ngAfterContentChecked() 之后調(diào)用。每次做完組件視圖和子視圖的變更檢測(cè)之后調(diào)用。
ngOnDestroy()在 Angular 銷毀指令/組件之前調(diào)用。當(dāng) Angular 每次銷毀指令/組件之前調(diào)用并清掃。 在這兒反訂閱可觀察對(duì)象和分離事件處理器,以防內(nèi)存泄漏。
取消訂閱可觀察對(duì)象、
清除定時(shí)器、
反注冊(cè)該指令在全局或應(yīng)用服務(wù)中注冊(cè)過的所有回調(diào)。
很重要

重點(diǎn)生命周期詳解

初始化組件和指令 ngOnInit

  • 在構(gòu)造函數(shù)外部執(zhí)行復(fù)雜的初始化。組件的構(gòu)造應(yīng)該既便宜又安全。比如,你不應(yīng)該在組件構(gòu)造函數(shù)中獲取數(shù)據(jù)。當(dāng)在測(cè)試中創(chuàng)建組件時(shí)或者決定顯示它之前,你不應(yīng)該擔(dān)心新組件會(huì)嘗試聯(lián)系遠(yuǎn)程服務(wù)器。ngOnInit() 是組件獲取初始數(shù)據(jù)的好地方

  • 在 Angular 設(shè)置好輸入屬性之后設(shè)置組件。構(gòu)造函數(shù)應(yīng)該只把初始局部變量設(shè)置為簡單的值。請(qǐng)記住,只有在構(gòu)造完成之后才會(huì)設(shè)置指令的數(shù)據(jù)綁定輸入屬性。如果要根據(jù)這些屬性對(duì)指令進(jìn)行初始化,請(qǐng)?jiān)谶\(yùn)行 ngOnInit() 時(shí)設(shè)置它們

在實(shí)例銷毀時(shí)進(jìn)行清理 ngOnDestroy

這里是釋放資源的地方,這些資源不會(huì)自動(dòng)被垃圾回收。如果你不這樣做,就存在內(nèi)存泄漏的風(fēng)險(xiǎn)。

  • 取消訂閱可觀察對(duì)象和 DOM 事件。

  • 停止 interval 計(jì)時(shí)器。

  • 反注冊(cè)該指令在全局或應(yīng)用服務(wù)中注冊(cè)過的所有回調(diào)。

  • ngOnDestroy() 方法也可以用來通知應(yīng)用程序的其它部分,該組件即將消失

頁面埋點(diǎn)

可以在組件中通過ngOnInit和ngOnDestroy方法統(tǒng)計(jì)頁面的時(shí)長,

更好的做法可以通過指令實(shí)現(xiàn)ngOnInit和ngOnDestroy生命周期,用來統(tǒng)計(jì)頁面時(shí)長

也可以通過路由守衛(wèi)來記錄頁面出入棧所需要的時(shí)間

@Directive({selector: '[appSpy]'})
export class SpyDirective implements OnInit, OnDestroy {

  constructor(private logger: LoggerService) { }

  ngOnInit()    { this.logIt(`onInit`); }

  ngOnDestroy() { this.logIt(`onDestroy`); }

  private logIt(msg: string) {
    this.logger.log(`Spy #${nextId++} ${msg}`);
  }
}

使用變更檢測(cè)鉤子 ngOnchanges

一旦檢測(cè)到該組件或指令的輸入屬性發(fā)生了變化,Angular 就會(huì)調(diào)用它的 ngOnChanges() 方法。

因?yàn)檫@個(gè)方法會(huì)頻繁執(zhí)行,所以要注意判斷的計(jì)算量,會(huì)影響性能。

// 可以監(jiān)聽輸入屬性的變化
ngOnChanges(changes: SimpleChanges) {
  for (const propName in changes) {
    const chng = changes[propName];
    const cur  = JSON.stringify(chng.currentValue);
    const prev = JSON.stringify(chng.previousValue);
    this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
  }
}

組件之間的通信(重要,必須掌握)

一、父子組件的通信(基礎(chǔ))

父傳子

1、父組件通過屬性綁定向子組件傳值

import { Component } from '@angular/core';
@Component({
  selector: 'app-parent',
  template: `
    <app-child [msg]="msg"></app-child>
  `
})
export class ParentComponent {
  msg = '父組件傳的值';
}

2、子組件通過@Input接收數(shù)據(jù)

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

@Component({
  selector: 'app-child',
  template: `
    <p>{{msg}}</p>
  `
})
export class ChildComponent {
  @Input() msg: String;
}

子傳父

1、子組件通過自定義事件,向父組件發(fā)送數(shù)據(jù)

import { Component, Input, EventEmitter, Output} from '@angular/core';
,
@Component({
  selector: 'app-child',
  template: `
    <p>{{msg}}</p>
    <button (click)="vote()" >發(fā)送</button>
  `
})
export class ChildComponent {
  @Input() msg: String;
  @Output() voted = new EventEmitter<boolean>();
  
  vote() {
    this.voted.emit("子組件傳的值");
  }
}

2、父組件通過監(jiān)聽自定義事件,接收子組件的傳值

import { Component } from '@angular/core';
@Component({
  selector: 'app-parent',
  template: `
    <app-child [msg]="msg" (voted)="voted($event)"></app-child>
  `
})
export class ParentComponent {
  msg = '父組件傳的值';
  voted(val){ //監(jiān)聽自定義事件的傳值
      console.log(val)
  }
}

子組件怎么監(jiān)聽輸入屬性值的變化?(2種方法)

1、可以使用一個(gè)輸入屬性@Input()的 setter,以攔截父組件中值的變化。

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

@Component({
  selector: 'app-child',
  template: '<h4>"{{name}}"</h4>'
})
export class ChildComponent {
  @Input()
  get name(): string { return this._name; }
  set name(name: string) {
    this._name = (name && name.trim()) || '<no name set>';
  }
  private _name = '';
}

2、通過ngOnChange()來截聽輸入屬性值的變化

當(dāng)需要監(jiān)視多個(gè)、交互式輸入屬性的時(shí)候,本方法比用屬性的 setter 更合適。

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-version-child',
  template: `
    <h4>Version {{major}}.{{minor}}</h4>
    <h5>Change log:</h5>
    <ul>
      <li *ngFor="let change of changeLog">{{change}}</li>
    </ul>
  `
})
export class VersionChildComponent implements OnChanges {
  @Input() major: number;
  @Input() minor: number;
  changeLog: string[] = [];

  ngOnChanges(changes: SimpleChanges) { //ngOnchange適合監(jiān)聽子組件多個(gè)輸入屬性的變化
    const log: string[] = [];
    for (const propName in changes) {
      const changedProp = changes[propName];
      const to = JSON.stringify(changedProp.currentValue);
      if (changedProp.isFirstChange()) {
        log.push(`Initial value of ${propName} set to ${to}`);
      } else {
        const from = JSON.stringify(changedProp.previousValue);
        log.push(`${propName} changed from ${from} to ${to}`);
      }
    }
    this.changeLog.push(log.join(', '));
  }
}

父組件怎么讀取子組件的屬性和調(diào)用子組件的方法?(2種方法)

1、通過本地變量代表子組件

父組件不能使用數(shù)據(jù)綁定來讀取子組件的屬性或調(diào)用子組件的方法。但可以在父組件模板里,新建一個(gè)本地變量來代表子組件,然后利用這個(gè)變量來讀取子組件的屬性和調(diào)用子組件的方法,如下例所示。

思考:父組件可以通過這種方式讀取子組件的私有屬性和私有方法嗎?

父組件

import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';

@Component({
  selector: 'app-countdown-parent-lv',
  template: `
  <h4>Countdown to Liftoff (via local variable)</h4>
  <button (click)="timer.start()">Start</button> //調(diào)用子組件方法
  <button (click)="timer.stop()">Stop</button>
  <div class="seconds">{{timer.seconds}}</div> //讀取子組件屬性
  <app-countdown-timer #timer></app-countdown-timer>
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownLocalVarParentComponent { }

子組件

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

@Component({
  selector: 'app-countdown-timer',
  template: '<p>{{message}}</p>'
})
export class CountdownTimerComponent implements OnDestroy {

  intervalId = 0;
  message = '';
  seconds = 11;

  ngOnDestroy() { this.clearTimer(); }

  start() { this.countDown(); }
  stop()  {
    this.clearTimer();
    this.message = `Holding at T-${this.seconds} seconds`;
  }

  private clearTimer() { clearInterval(this.intervalId); }

  private countDown() {
    this.clearTimer();
    this.intervalId = window.setInterval(() => {
      this.seconds -= 1;
      if (this.seconds === 0) {
        this.message = 'Blast off!';
      } else {
        if (this.seconds < 0) { this.seconds = 10; } // reset
        this.message = `T-${this.seconds} seconds and counting`;
      }
    }, 1000);
  }
}

2、父組件調(diào)用@viewChild() (基礎(chǔ),推薦使用)

這個(gè)本地變量方法是個(gè)簡單便利的方法。但是它也有局限性(只能在模板html中使用),因?yàn)楦附M件-子組件的連接必須全部在父組件的模板中進(jìn)行。父組件本身的ts代碼對(duì)子組件沒有訪問權(quán)。

當(dāng)父組件類需要訪問子組件時(shí),可以把子組件作為 ViewChild,注入到父組件里面。

父組件類中訪問子組件的屬性和方法:

import { AfterViewInit, ViewChild } from '@angular/core';
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component'; //引入子組件

@Component({
  selector: 'app-countdown-parent-vc',
  template: `
  <h4>Countdown to Liftoff (via ViewChild)</h4>
  <button (click)="start()">Start</button>
  <button (click)="stop()">Stop</button>
  <div class="seconds">{{ seconds() }}</div>
  <app-countdown-timer></app-countdown-timer>
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {

  //通過 @ViewChild 屬性裝飾器,將子組件 CountdownTimerComponent 注入到私有屬性 timerComponent 里面。
  @ViewChild(CountdownTimerComponent) 
  private timerComponent: CountdownTimerComponent;

  seconds() { return 0; }

  // angular創(chuàng)建了組件的子視圖后會(huì)調(diào)用它,注意獲取子組件的屬性,要在子組件視圖加載之后
  ngAfterViewInit() {
    // 訪問子組件屬性
    setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
  }

  start() { this.timerComponent.start(); } // 訪問子組件的方法
  stop() { this.timerComponent.stop(); }
}

注意:(使用場(chǎng)景很多,必須掌握)

ngAfterViewInit() 生命周期鉤子是非常重要的一步。被注入的計(jì)時(shí)器組件只有在 Angular 顯示了父組件視圖之后才能訪問,所以它先把秒數(shù)顯示為 0.

然后 Angular 會(huì)調(diào)用 ngAfterViewInit 生命周期鉤子,但這時(shí)候再更新父組件視圖的倒計(jì)時(shí)就已經(jīng)太晚了。Angular 的單向數(shù)據(jù)流規(guī)則會(huì)阻止在同一個(gè)周期內(nèi)更新父組件視圖。應(yīng)用在顯示秒數(shù)之前會(huì)被迫再等一輪。

使用 setTimeout() 來等下一輪,然后改寫 seconds() 方法,這樣它接下來就會(huì)從注入的這個(gè)計(jì)時(shí)器組件里獲取秒數(shù)的值。

二、組件通過服務(wù)來通信(發(fā)布訂閱者模式,基礎(chǔ),必須掌握)

父組件和它的子組件共享同一個(gè)服務(wù),利用該服務(wù)在組件家族內(nèi)部實(shí)現(xiàn)雙向通信。

不僅局限于父子組件,只要組件與組件共享同一個(gè)服務(wù),就可以實(shí)現(xiàn)數(shù)據(jù)通信。

<!--parent.component.html-->
<p style="width: 1000px;margin: auto">
<p class="card" style="width: 500px;float: left">
 <p class="card-header"> 父組件</p>

 <p class="card-body">
  <h6 class="card-title">父組件</h6>
  <p class="form-group">
   <label for="serviceoutput">父組件服務(wù)輸入:</label>
   <input type="text"
       class="form-control"
       id="serviceoutput"
       placeholder="服務(wù)輸入"
       [(ngModel)]="serviceInput"
   >
  </p>

  <button class="btn btn-primary" (click)="clickService()">Service方式</button>
 </p>

</p>
<app-child></app-child>
</p>
<!--child.component.html-->
<p class="card" style="width: 500px;">
 <p class="card-header">子組件</p>

 <p class="card-body">
  <h6 class="card-title">子組件</h6>
  <p class="form-group">
   <label for="serviceoutput">子組件服務(wù)輸入:</label>
   <input type="text"
       class="form-control"
       id="serviceoutput"
       placeholder="服務(wù)輸入"
       [(ngModel)]="serviceInput"
   >
  </p>

  <button class="btn btn-primary" (click)="clickService()">Service方式</button>
 </p>
</p>
//服務(wù)重點(diǎn)
//meditor.service.ts

import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class MeditorService {
 private subject = new Subject<MeditorMsg>();
 constructor() {}
 // 獲取訂閱者
 public getObservable(): Observable<MeditorMsg> {
  return this.subject.asObservable();
 }

 // 推送信息
 public push(msg: MeditorMsg) {
  this.subject.next(msg);
 }
}

// 中間者信息
export interface MeditorMsg {
 id: string;
 body: any;
}
subscription: Subscription = null; //初始化一個(gè)訂閱對(duì)象

//子組件構(gòu)造函數(shù),用于監(jiān)聽數(shù)據(jù)推送
constructor(private meditor: MeditorService) {
  this.subscription = meditor.getObservable().subscribe(
   msg => {
    console.log(msg);
    if (msg.id === 'parent') {   //id為parent,獲取父組件數(shù)據(jù)
     this.serviceInput = msg.body;
    }
   }
  );
 }
// 子組件將數(shù)據(jù)推送到中間著,給訂閱者
clickService() {
  this.meditor.push({id: 'parent', body: this.serviceInput});
 }

//父組件構(gòu)造函數(shù),用于監(jiān)聽數(shù)據(jù)推送
constructor(private meditor: MeditorService) {
  this.subscription = meditor.getObservable().subscribe(
   msg => {
    console.log(msg);
    if (msg.id === 'child') {    //id為child,獲取子組件數(shù)據(jù)
     this.serviceInput = msg.body;
    }
   }
  );
 }

// 父組件將數(shù)據(jù)推送到中間著,給訂閱者
clickService() {
  this.meditor.push({id: 'parent', body: this.serviceInput});
 }
 
// 注意:訂閱一個(gè)對(duì)象,就是在生命周期結(jié)束前,要取消訂閱。
ngOnDestroy() {
    this.subscription.unsubscribe();
}

思考: 這種發(fā)布訂閱者模式適合全局狀態(tài)管理嗎?

三、可以通過本地緩存來實(shí)現(xiàn)通信(Cookie,LocalStorage、SessionStorage)

<!-- catch_namae_type.ts -->
// 目的是好維護(hù)
// 項(xiàng)目當(dāng)中用到的頁面緩存,需要在這里進(jìn)行聲明;key-value保持一致
// 聲明規(guī)則,不同類型的緩存使用前綴 session_/ local_ / cookie_
// 動(dòng)態(tài)設(shè)置緩存不用在這里聲明,但是需要在key后面加'_noSetType_'標(biāo)識(shí)
export const CatchNameType = {
  session_userInfo: 'session_userInfo', // 用戶信息
  session_toekn: 'session_token', // token
  local_loginInfo: 'local_loginInfo', // 本地緩存用戶名密碼
};

<!--catch.ts-->
import { Injectable } from '@angular/core';
// 定義這個(gè)類,主要是看全局定義了哪些本地緩存
import { CatchNameType } from './catch_namae_type';

// -------------------------------------------------------緩存工具類(三類方法)
// Cookie           (方法有:set/get/remove)
// SStorage(sessionStorage)  (方法有:set/get/remove/clear)
// LStorage(localStorage)    (方法有:set/get/remove/clear)
@Injectable({
  providedIn: 'root',
})
export class Catch {
  // cookie
  public static Cookie = {
    /**
     * cookie 存貯
     * @param key  屬性
     * @param value  值
     * @param String expire  過期時(shí)間,單位天
     */
    set(key: string, value: any, expire: any): void {
      if (Catch.is_set_catch_name_type(key)) {
        const d = new Date();
        d.setDate(d.getDate() + expire);
        document.cookie = `${key}=${value};expires=${d.toDateString()}`;
      }
    },
    get(key: string): string {
      const cookieStr = unescape(document.cookie);
      const arr = cookieStr.split('; ');
      let cookieValue = '';
      // tslint:disable-next-line: prefer-for-of
      for (let i = 0; i < arr.length; i++) {
        const temp = arr[i].split('=');
        if (temp[0] === key) {
          cookieValue = temp[1];
          break;
        }
      }
      return cookieValue;
    },
    remove(key: string): void {
      document.cookie = `${encodeURIComponent(key)}=;expires=${new Date()}`;
    },
  };

  // sessionStorage
  public static SStorage = {
    set(key: string, value: any): void {
      if (Catch.is_set_catch_name_type(key)) {
        sessionStorage.setItem(key, JSON.stringify(value));
      }
    },
    get(key: string): any {
      const jsonString =
        sessionStorage.getItem(key) === 'undefined'
          ? undefined
          : sessionStorage.getItem(key);
      return jsonString ? JSON.parse(jsonString) : null;
    },

    remove(key: string): void {
      sessionStorage.removeItem(key);
    },
    clear(): void {
      sessionStorage.clear();
    },
  };

  // localStorage
  public static LStorage = {
    set(key: string, value: any): void {
      if (Catch.is_set_catch_name_type(key)) {
        localStorage.setItem(key, JSON.stringify(value));
      }
    },
    get(key: string): any {
      const jsonString =
        localStorage.getItem(key) === 'undefined'
          ? undefined
          : localStorage.getItem(key);
      return jsonString ? JSON.parse(jsonString) : null;
    },
    remove(key: string): void {
      localStorage.removeItem(key);
    },
    clear(): void {
      localStorage.clear();
    },
  };

  // 設(shè)置緩存的時(shí)候是否在catch_name_type里面聲明
  static is_set_catch_name_type(key: string): boolean {
    let allow = false;
    // 對(duì)動(dòng)態(tài)設(shè)置緩存不進(jìn)行檢查
    if (key.indexOf('_noSetType_') !== -1) {
      allow = true;
      console.log('動(dòng)態(tài)設(shè)置緩存', key);
      return allow;
    }
    // 對(duì)命名規(guī)則進(jìn)行檢查
    const nameRule =
      key.indexOf('session_') !== -1 ||
      key.indexOf('local_') !== -1 ||
      key.indexOf('cookie_') !== -1;
    if (!nameRule) {
      allow = false;
      console.log('命名規(guī)則錯(cuò)誤', key);
      return allow;
    }
    // 靜態(tài)設(shè)置的緩存需要配置類型
    Object.values(CatchNameType).forEach((item) => {
      if (item === key) {
        allow = true;
      }
    });
    if (!allow) {
      console.log('緩存操作失敗,請(qǐng)檢查配置緩存類型');
    }
    return allow;
  }
}

四、頁面路由傳參也可以實(shí)現(xiàn)單向通信

這部分內(nèi)容,我會(huì)在路由章節(jié)整理。

組件通信總結(jié)

所以組件通信大概有如下幾種:

1、父子組件通信(1、@Input() @output 2、本地變量#val 3、@viewChild())

2、通過服務(wù)

3、頁面緩存

4、頁面級(jí)組件傳參(兩個(gè)頁面等同于兩個(gè)組件)

動(dòng)態(tài)組件

組件的模板不會(huì)永遠(yuǎn)是固定的。應(yīng)用可能會(huì)需要在運(yùn)行期間按需加載一些新的組件。 通過下面的例子可以了解動(dòng)態(tài)組件的基本使用

1、創(chuàng)建組件,被引入的組件

@Component({
  template: `<span>hello world</span>`
})
export class DynamicComponent { }

2、創(chuàng)建容器組件,用于加載動(dòng)態(tài)組件

@Component({
  selector: 'app-container',
  template: `
    <div #dynamicContainer></div>
    <button (click)="createComponent()">Create</button>
  `
})
export class AppContainerComponent {
  // 聲明容器
  @ViewChild("dynamicContainer", { read: ViewContainerRef }) container: ViewContainerRef;
}

在AppContainerComponent組件中,通過@ViewChild裝飾器來獲取視圖中的模板元素,如果沒有指定第二個(gè)查詢參數(shù),則默認(rèn)返回 組件實(shí)例或相應(yīng)的DOM元素,但這個(gè)示例中,我們需要獲取ViewContainerRef實(shí)例也就是視圖容器。可以在視圖容器中創(chuàng)建、插入、刪除組件等。

3、動(dòng)態(tài)創(chuàng)建組件

在創(chuàng)建組件之前,需要注入ComponentFactoryResolver服務(wù)對(duì)象,該服務(wù)是動(dòng)態(tài)加載組件的核心,可以將一個(gè)組件實(shí)例呈現(xiàn)到另一個(gè) 組件視圖上。

  • 使用ComponentFactoryResolve將已聲明但未實(shí)例化的組件解析成為可以動(dòng)態(tài)加載的component

//依賴組件類型獲取對(duì)應(yīng)的factory,從名字上可以看出該factory是用來初始化組件的
const componentFactory = this.ComponentFactoryResolver(DynamicComponent);
//調(diào)用視圖容器的createComponent方法并將組件添加到容器上。該方法內(nèi)部會(huì)調(diào)用factory的create方法來初始化組件。
const modalContainerRef = this.container.createComponent(componentFactory);

4、為組件屬性賦值

通過如下的方式為組件屬性進(jìn)行賦值

modalContainerRef.instance.property = ***;

5、銷毀組件

在使用組件后,記得要銷毀組件。

modalContainerRef.destroy();

6、組件注冊(cè)

為了能夠動(dòng)態(tài)創(chuàng)建組件需要將組件在模塊的entryComponents中聲明。因?yàn)樵趀ntryComponents中聲明的組件Angular都會(huì)創(chuàng)建一個(gè) ComponentFactory并將其存儲(chǔ)在ComponentFactoryResolver中,這是動(dòng)態(tài)加載必需的步驟。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“angular10組件的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI