Angular-我的整理

  1. 單向從數據源到視圖
{{expression}}
[target]="expression"
bind-target="expression"
複製代碼

單向從視圖到數據源css

(target)="statement"
on-target="statement"
複製代碼

雙向html

[(target)]="expression"
bindon-target="expression"
複製代碼
  1. DOM property 的值能夠改變;HTML attribute 的值不能改變。
    Angular 的世界中,attribute 惟一的做用是用來初始化元素和指令的狀態。
    當進行數據綁定時,只是在與"元素和指令"的 "property 和事件"打交道,而 attribute 就徹底靠邊站了。express

  2. 若是忘了加方括號Angular 會把這個表達式當作字符串常量看待,並用該字符串來初始化目標屬性。
    下面這個例子把 HeroDetailComponentprefix 屬性初始化爲固定的字符串"1+1",而不是模板表達式"2"。Angular 設置它,而後忘記它。json

<app-hero-detail prefix="1+1" [hero]="currentHero"></app-hero-detail>
複製代碼

做爲對比,[hero] 綁定是組件的 currentHero 屬性的活綁定,它會一直隨着更新bootstrap

  1. 插值表達式 {{...}} ,先對雙花括號中的表達式求值,再把求值的結果轉換成字符串
    實際上,在渲染視圖以前,Angular 把這些插值表達式翻譯成了相應的屬性綁定。
  • 注意:但數據類型不是字符串時,就必須使用屬性綁定了。
<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>
複製代碼
  1. 不論是插值表達式仍是屬性綁定,都不會容許帶有 script 標籤的 HTML 泄漏到瀏覽器中,兩者都只渲染沒有危害的內容。
src/app/app.component.ts
    evilTitle = 'Template <script>alert("evil never sleeps")</script>Syntax';
src/app/app.component.html  
    <p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p>
    <p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>

複製代碼
  1. attribute 綁定
    通常狀況下,咱們經過屬性綁定來設置元素的屬性property,而不用字符串設置元素的attribute
    但考慮 ARIASVGtable 中的 colspan/rowspanattribute。 它們是純粹的 attribute沒有對應的屬性可供綁定。 若是想寫出相似下面這樣的東西,就會暴露出痛點了:
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
複製代碼

會獲得這個錯誤:
Template parse errors: Can't bind to 'colspan' since it isn't a known native property
方括號中的部分不是元素的屬性名,而是由attr前綴,一個點 (.)attribute 的名字組成segmentfault

<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
複製代碼
  1. 雙向數據綁定 ( [(...)] )

雙向綁定語法其實是屬性綁定和事件綁定的語法糖。數組

  1. 內置屬性型指令
  • a.經過綁定到 NgClass,能夠同時添加或移除多個類。 把 ngClass 綁定到一個 key:value 形式的控制對象valueboolean值)

src/app/app.component.html瀏覽器

<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special</div>
複製代碼

src/app/app.component.ts安全

currentClasses: {};
    setCurrentClasses() {
      // CSS classes: added/removed per current state of component properties
      this.currentClasses =  {
        'saveable': this.canSave,
        'modified': !this.isUnchanged,
        'special':  this.isSpecial
      };
    }
複製代碼
  • b.經過綁定NgStyle設置多個內聯樣式。NgStyle 須要綁定到一個 key:value 控制對象。 src/app/app.component.html
<div [ngStyle]="currentStyles">
    This div is initially italic, normal weight, and extra large (24px).
    </div>
複製代碼

src/app/app.component.tsbash

currentStyles: {};
    setCurrentStyles() {
      // CSS styles: set per current state of component properties
      this.currentStyles = {
        'font-weight': 'bold',
      };
    }
複製代碼
  1. 模板輸入變量和模板引用變量
  • 模板輸入變量
    hero 前的 let 關鍵字建立了一個名叫 hero 的模板輸入變量。 這個變量的範圍被限制在所重複模板的單一實例上。事實上,你能夠在其它內置結構型指令中使用一樣的變量名。
  • 模板引用變量
    #phone 的意思就是聲明一個名叫 phone 的變量來引用 <input> 元素。 模板引用變量的做用範圍是整個模板。不要在同一個模板中屢次定義同一個變量名,不然它在運行期間的值是沒法肯定的。
<input #phone placeholder="phone number">
複製代碼
  1. 你老是能夠在"組件本身的模板"中綁定到組件的公共屬性,而不用管它們是否輸入(Input)屬性或輸出(Output)屬性。 但Angular 須要@Input()@Output()裝飾器來標記出那些容許被外部組件綁定到的屬性。 聲明輸入與輸出屬性:
@Input()  hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();
複製代碼

另外:@Input get/set寫法

_oprType: string ='VIEW';
@Input("oprType")
get oprType(){
    retrun this._oprType;
}
set oprType(oprType){
    this._oprType = oprType;
    ...//其餘邏輯處理
}
複製代碼
  1. json 管道對調試綁定特別有用:
src/app/app.component.html (pipes-json)
      <div>{{currentHero | json}}</div>
複製代碼

它生成的輸出是這樣的:

{ "id": 0, "name": "Hercules", "emotion": "happy",
  "birthdate": "1970-02-25T08:00:00.000Z",
  "url": "http://www.imdb.com/title/tt0065832/",
  "rate": 325 }
複製代碼
  1. 生命週期
  • 注意:構造函數在全部的生命週期鉤子以前執行

ngOnChanges()-》ngOnInit()-》ngDoCheck()-》ngAfterContentInit()-》ngAfterContentChecked()-》ngAfterViewInit()-》ngAfterViewChecked()-》ngOnDestroy()

ngOnInit 生命週期鉤子會在 DOM 更新操做執行前觸發

  1. rxjs知識
var subject = new Subject<string>();
subject.next(1);
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
//observerA: 1
複製代碼
  1. 純(pure)管道與非純(impure)管道
    默認狀況下,管道都是純的。 Angular 只有在它檢測到輸入值發生了純變動時纔會執行純管道。
    純變動:是指對原始類型值(String、Number、Boolean、Symbol)的更改,或者對對象引用(Date、Array、Function、Object)的更改。
    Angular 會忽略對象內部的更改。 若是你更改了輸入日期(Date)中的月份、往一個輸入數組(Array)中添加新值或者更新了一個輸入對象(Object)的屬性,Angular 都不會調用純管道。
    Angular 會在每一個組件的變動檢測週期中執行非純管道。 非純管道可能會被調用不少次,和每一個按鍵或每次鼠標移動同樣頻繁。

  2. ElementRef

import { Directive, ElementRef } from '@angular/core';
@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'yellow';
    }
}
複製代碼

import 語句還從 Angularcore 庫中導入了一個 ElementRef 符號。
你能夠在指令的構造函數中注入 ElementRef,來引用宿主 DOM 元素。 ElementRef(對視圖中某個宿主元素的引用)經過其 nativeElement 屬性給了你直接訪問宿主 DOM 元素的能力。

  • 注意:容許直接訪問 DOM 會致使你的應用在 XSS 攻擊前面更加脆弱。當須要直接訪問 當須要直接訪問 DOM 時,請把本 API 做爲最後選擇


優先使用 Angular 提供的模板和數據綁定機制。 或者你還能夠看看 Renderer2(實現自定義渲染器),它提供了可安全使用的 API —— 即便環境沒有提供直接訪問原生元素的功能。

import { Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(el: ElementRef, private renderer: Renderer2) {
       //el.nativeElement.style.backgroundColor = 'yellow';
       this.renderer.setStyle(this.el.nativeElement, "backgroundColor", 'yellow');
    }
}
複製代碼

ViewChild和ElementRef

  1. HostListener把一個事件綁定到一個宿主監聽器,並提供配置元數據。
@HostListener('mousedown') onMouseEnter() {
  this.highlight(this.highlightColor || this.defaultColor || 'red');
}
複製代碼

mousedown要監聽的事件。 當mousedown事件發生時,Angular 就會執行所提供的處理器方法onMouseEnter

  1. 你能夠根據屬性名在綁定中出現的位置來斷定是否要加 @Input
    當它出如今等號右側的模板表達式中時,它屬於模板所在的組件,不須要 @Input 裝飾器。
    當它出如今等號左邊的方括號([ ])中時,該屬性屬於其它組件或指令,它必須帶有 @Input 裝飾器。
<p [appHighlight]="color">Highlight me!</p>  
複製代碼

color 屬性位於右側的綁定表達式中,它屬於模板所在的組件。 該模板和組件相互信任。所以 color 不須要 @Input 裝飾器。
appHighlight 屬性位於左側,它引用了 HighlightDirective 中一個帶別名的屬性,它不是模板所屬組件的一部分,所以存在信任問題。 因此,該屬性必須帶 @Input 裝飾器。

  1. bootstrap —— 根組件,Angular 建立它並插入 index.html 宿主頁面。
  2. 結構型指令中,星號(*)寫法是個語法糖,Angular會把它解開成一個 <ng-template> 標記,包裹着宿主元素及其子元素。 Angular 會在真正渲染的時候填充 <ng-template> 的內容,而且把 <ng-template> 替換爲一個供診斷用的註釋。
<ng-template let-hero="hero">
  <div *ngIf="hero" [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
複製代碼
  • 注意:若是沒有使用結構型指令,而僅僅把一些別的元素包裝進 <ng-template> 中,那些元素就是不可見的(被註釋掉了)。
  1. 每一個宿主元素上只能有一個結構型指令。好比:*ngFor*ngIf 不能放在同一個宿主元素上。
    有一個簡單的解決方案:把 *ngFor 放在一個"容器"元素上,再包裝進 *ngIf 元素。 這個元素可使用ng-container,以避免引入一個新的 HTML 層級。
<ul>
  <ng-container *ngFor="let menu of menus">
    <li *ngIf="!menu.children?.length">
    </li>
  </ng-container>
</ul>
複製代碼

Angular<ng-container> 是一個分組元素,但它不會污染樣式或元素佈局,由於 Angular 壓根不會把它放進 DOM 中。

template: <ng-template #toolbarTemplate [ngTemplateOutletContext]="{ $implicit: this}"></ng-template> 
class: @ViewChild("toolbarTemplate") toolbarTemplate: TemplateRef<any>
簡化寫法:
<ng-template [ngTemplateOutlet]="toolbarTemplate || defaultToolbarTemplate"
               [ngTemplateOutletContext]="{ $implicit: this}"></ng-template>
複製代碼

該指令用於基於已有的 TemplateRef 對象,插入對應的內嵌視圖。在應用 NgTemplateOutlet 指令時,咱們能夠經過 [ngTemplateOutletContext] 屬性來設置 EmbeddedViewRef 的上下文對象。綁定的上下文應該是一個對象,此外可經過 let語法來聲明綁定上下文對象屬性名。

angular6.x中ngTemplateOutlet指令的使用示例

  1. 表達式中的上下文變量是由"模板引用變量#aa"、"模板輸入變量let bb"和"組件的成員cc"疊加而成的。
    優先級:模板輸入變量>模板引用變量>指令的上下文變量>組件類的實例

  2. 模板表達式不能引用全局命名空間中的任何東西,好比windowdocument。它們也不能調用console.logMath.max。它們只能引用表達式上下文中的內容。

  3. 聲明式組件和入口組件:
    聲明式組件會在模板中經過組件聲明的selector(好比<cmb></cmb>)加載組件。
    入口組件entryComponents主要有3類:

  • @NgModule中的bootstrap聲明的根組件
  • 路由配置的組件
  • 動態組件
  1. exports
    在模塊angModuleexports出一組組件、指令和管道
    -》模板b導入了模塊a
    -》模塊b下的全部組件的模板,均可以使用模塊angModuleexports出的組件、指令和管道
  2. 父子組件交互
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
複製代碼

這個本地變量方法#timer是個簡單便利的方法。可是它也有侷限性,由於父組件-子組件的鏈接必須所有在父組件的html模板中進行。父組件自己的ts代碼對子組件沒有訪問權。
父組件ts須要這種訪問時,能夠把子組件做爲 ViewChild,注入到父組件裏面。@ViewChild('timer') timer;

  1. 內容投影ng-content

父組件頁面parent.html

<attchment-upload>abcde</attchment-upload>
複製代碼

被父組件包含的子組件標籤頁面attchment-upload.html

<div>-- begins --</div>
    <ng-content></ng-content>
  <div>-- ends --</div>`
複製代碼

輸出:

-- begins --
abcde
-- ends --
複製代碼

以上<ng-content> 標籤是父組件頁面中外來內容的佔位符。 它指明在子組件標籤頁面的哪裏插入這些父組件的外來內容abcde

注意不要在組件標籤的內部聽任何內容 —— 除非你想把這些內容投影進這個組件中。

  1. NgTemplateOutlet基於已有的TemplateRef 對象,插入對應的內嵌視圖。 Angular 4.x NgTemplateOutlet
<ng-container *ngTemplateOutlet="greet"></ng-container>
<ng-template #greet><span>Hello</span></ng-template>
複製代碼

或者

<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
contentTemplate:TemplateRef<any>
this.contentTemplate=...
//TemplateRef就是對應html中的ng-template標籤
複製代碼
  1. ngIf寫法
<ng-container *ngIf="a.length==0; else elseTemplate">
    ...
</ng=container>
<ng-template #elseTemplate>
    ...
</ng-template>
複製代碼

30.ngTemplateOutletContext

<ng-template let-rowData let-rowIndex="rowIndex" let-columns="columns">
    <tr>
        <td *ngFor="let col of columns;">
            // 經過 [ngTemplateOutletContext] 屬性來設置 EmbeddedViewRef:commonBodyTemplate的上下文對象
            <ng-container *ngTemplateOutlet="commonBodyTemplate;context:{$implicit:col,rowIndex:rowIndex,rowData:rowData,columns:columns}"></ng-container>
        </td>
    </tr>
</ng-template>

//若 let 語法未綁定任何屬性名(let-col),則上下文對象中 $implicit 屬性,對應的值col將做爲默認值。
<ng-template #commonBodyTemplate let-col let-rowIndex="rowIndex" let-rowData="rowData">
    <ng-container *ngIf="col.field=='idx'">
        {{rowIndex+1}}
    </ng-container>
    <ng-container *ngIf="col.field=='attachSize'">
        {{(rowData[col.field]||"--")+(rowData["attachSizeUnit"]||"")}}
    </ng-container>
    <ng-container *ngIf="editable;else elseTemplate">
        <ng-container *ngIf="col.field=='fileName'">
            <ng-container *ngIf="rowData['attachmentId']">
                <a [href]="attachUrls[rowData['attachmentId']]" [download]="rowData[col.field]">{{rowData[col.field]||""}}</a>
            </ng-container>
        </ng-container>
        <ng-container *ngIf="['idx','attachSize','fileName'].indexOf(col.field)==-1">
            {{rowData[col.field]||"--"}}
        </ng-container>
    </ng-container>
    <ng-template #elseTemplate>
        <ng-container *ngIf="['idx','attachSize'].indexOf(col.field)==-1">
            {{rowData[col.field]||"--"}}
        </ng-container>
    </ng-template>
</ng-template>
複製代碼

在父頁面中嵌入<app-attachment></app-attachment>
報錯:"app-attachment" is not a unknown element.
緣由:app-attachment子頁面模板對應的ts組件沒有包括在父頁面所在的module中。

32.@Input('companyId') companyId: string; 子組件的初始化constructor取不到companyId值,ngOnInit()能夠 因此初始化放在ngOnInit中。

33.響應式表單

this.formGroup=fb.group({
        contractid:["123",[Validators.required]],
});

this.theDetailGroup.get("finProductName").setValue(this.finProductName);
this.formGroup.get("docmentId").valueChanges.subscribe(value=>{
          if(this.existList.findIndex(item=>item.docmentId==value)>-1){
            this.formGroup.get("docmentId").setErrors({duplicate:true});
          }
        });
        
this.formGroup.get("docmentId").value; 
複製代碼

34.this.fb.group({}) 響應式表單控件綁定,應該在生命週期以前,即constructor構造函數中初始化。由於若是放在ngOnInit中綁定,在表單初始化前對錶單進行賦值操做,會報錯。

35.自定義模塊中exports使用

將附件聲明到公用模塊

import { NgModule } from '@angular/core';
import { CommonModule} from '@angular/common';
import { AttachmentComponent } from './attachment.component';

@NgModule({
  imports: [
    CommonModule,
  ],
  exports:[
    CommonModule,
    AttachmentComponent
  ],
  providers:[],
  declarations: [
    AttachmentComponent
  ],
  entryComponents:[
    AttachmentComponent
  ]
})
export class SharedModule { }

複製代碼

宿主組件所在的module中引入公共模塊

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/shared';



@NgModule({
  declarations: [
     ],
  imports: [
    CommonModule,
    SharedModule
  ],
  entryComponents:[]
})
export class MineModule { }

複製代碼

36.自定義雙向數據綁定

  • 父組件
<app-base [(companyId)]="companyId"></app-base>
複製代碼
  • 子組件app-base.ts
_companyId = '';
  @Output() companyIdChange = new EventEmitter();
  @Input('companyId')
  get companyId() {
    return this._companyId;
  }
  set companyId(companyId) {
    this._companyId = companyId;
    this.companyIdChange.emit(companyId);
  }
複製代碼

注意:屬性名 + Change是雙向綁定中Output的固定寫法

37.在使用一些第三方的組件的時候,要修改組件的樣式。 這種狀況下使用:

:host ::ng-deep .className{
    新的樣式......
}
複製代碼

38.要在html直接使用某個變量。ts中能夠不要定義這個變量,直接get

html:
<div *ngIf="isStatusOkey"></div>
ts:
get isStatusOkey() {
return this.baseInfoConfig.baseInfoData['lpIndentifyStatus'] !== 'OKAY';
}
html:
<mat-grid-tile *ngFor="let item of attachmentTypeList"></mat-grid-tile> ts: get attachmentTypeList() { return this.attachService.getAttachmentTypeList(); } 複製代碼
相關文章
相關標籤/搜索