Angular開發實踐(三):剖析Angular Component

来源:https://www.cnblogs.com/laixiangran/archive/2018/03/22/8624768.html
-Advertisement-
Play Games

Web Component 在介紹Angular Component之前,我們先簡單瞭解下 "W3C Web Components" 定義 W3C為統一組件化標準方式,提出Web Component的標準。 每個組件包含自己的html、css、js代碼。 Web Component標準包括以下四個重 ...


Web Component

在介紹Angular Component之前,我們先簡單瞭解下W3C Web Components

定義

  • W3C為統一組件化標準方式,提出Web Component的標準。
  • 每個組件包含自己的html、css、js代碼。
  • Web Component標準包括以下四個重要的概念:
  1. Custom Elements(自定義標簽):可以創建自定義 HTML 標記和元素;
  2. HTML Templates(HTML模版):使用 <template> 標簽去預定義一些內容,但並不載入至頁面,而是使用 JS 代碼去初始化它;
  3. Shadow DOM(虛擬DOM):可以創建完全獨立與其他元素的DOM子樹;
  4. HTML Imports(HTML導入):一種在 HTML 文檔中引入其他 HTML 文檔的方法,<link rel="import" href="example.html" />

概括來說就是,可以創建自定義標簽來引入組件是前端組件化的基礎,在頁面引用 HTML 文件和 HTML 模板是用於支撐編寫組件視圖和組件資源管理,而 Shadow DOM 則是隔離組件間代碼的衝突和影響。

示例

定義hello-component

<template id="hello-template">
    <style>
        h1 {
            color: red;
        }
    </style>
    <h1>Hello Web Component!</h1>
</template>

<script>

    // 指嚮導入文檔,即本例的index.html
    var indexDoc = document;

    // 指向被導入文檔,即當前文檔hello.html
    var helloDoc = (indexDoc._currentScript || indexDoc.currentScript).ownerDocument;

    // 獲得上面的模板
    var tmpl = helloDoc.querySelector('#hello-template');

    // 創建一個新元素的原型,繼承自HTMLElement
    var HelloProto = Object.create(HTMLElement.prototype);

    // 設置 Shadow DOM 並將模板的內容克隆進去
    HelloProto.createdCallback = function() {
        var root = this.createShadowRoot();
        root.appendChild(indexDoc.importNode(tmpl.content, true));
    };

    // 註冊新元素
    var hello = indexDoc.registerElement('hello-component', {
        prototype: HelloProto
    });
</script>

使用hello-component

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-COMPATIBLE" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="賴祥燃, [email protected], http://www.laixiangran.cn"/>
    <title>Web Component</title>
    <!--導入自定義組件-->
    <link rel="import" href="hello.html">
</head>
<body>
    <!--自定義標簽-->
    <hello-component></hello-component>
</body>
</html>

從以上代碼可看到,hello.html 為按標准定義的組件(名稱為 hello-component ),在這個組件中有自己的結構、樣式及邏輯,然後在 index.html 中引入該組件文件,即可像普通標簽一樣使用。

Angular Component

Angular Component屬於指令的一種,可以理解為擁有模板的指令。其它兩種是屬性型指令結構型指令

基本組成

@Component({
    selector: 'demo-component',
    template: 'Demo Component'
})
export class DemoComponent {}
  • 組件裝飾器:每個組件類必須用@component進行裝飾才能成為Angular組件。
  • 組件元數據:組件元數據:selectortemplate等,下文將著重講解每個元數據的含義。
  • 組件類:組件實際上也是一個普通的類,組件的邏輯都在組件類里定義並實現。
  • 組件模板:每個組件都會關聯一個模板,這個模板最終會渲染到頁面上,頁面上這個DOM元素就是此組件實例的宿主元素。

組件元數據

自身元數據屬性

名稱 類型 作用
animations AnimationEntryMetadata[] 設置組件的動畫
changeDetection ChangeDetectionStrategy 設置組件的變化監測策略
encapsulation ViewEncapsulation 設置組件的視圖包裝選項
entryComponents any[] 設置將被動態插入到該組件視圖中的組件列表
interpolation [string, string] 自定義組件的插值標記,預設是雙大括弧
moduleId string 設置該組件在 ES/CommonJS 規範下的模塊id,它被用於解析模板樣式的相對路徑
styleUrls string[] 設置組件引用的外部樣式文件
styles string[] 設置組件使用的內聯樣式
template string 設置組件的內聯模板
templateUrl string 設置組件模板所在路徑
viewProviders Provider[] 設置組件及其所有子組件(不含ContentChildren)可用的服務

從 core/Directive 繼承

名稱 類型 作用
exportAs string 設置組件實例在模板中的別名,使得可以在模板中調用
host {[key: string]: string} 設置組件的事件、動作和屬性等
inputs string[] 設置組件的輸入屬性
outputs string[] 設置組件的輸出屬性
providers Provider[] 設置組件及其所有子組件(含ContentChildren)可用的服務(依賴註入)
queries {[key: string]: any} 設置需要被註入到組件的查詢
selector string 設置用於在模板中識別該組件的css選擇器(組件的自定義標簽)

幾種元數據詳解

以下幾種元數據的等價寫法會比元數據設置更簡潔易懂,所以一般推薦的是等價寫法。

inputs

@Component({
    selector: 'demo-component',
    inputs: ['param']
})
export class DemoComponent {
    param: any;
}

等價於:

@Component({
    selector: 'demo-component'
})
export class DemoComponent {
    @Input() param: any;
}

outputs

@Component({
    selector: 'demo-component',
    outputs: ['ready']
})
export class DemoComponent {
    ready = new eventEmitter<false>();
}

等價於:

@Component({
    selector: 'demo-component'
})
export class DemoComponent {
    @Output() ready = new eventEmitter<false>();
}

host

@Component({
    selector: 'demo-component',
    host: {
        '(click)': 'onClick($event.target)', // 事件
        'role': 'nav', // 屬性
        '[class.pressed]': 'isPressed', // 類
    }
})
export class DemoComponent {
    isPressed: boolean = true;

    onClick(elem: HTMLElement) {
        console.log(elem);
    }
}

等價於:

@Component({
    selector: 'demo-component'
})
export class DemoComponent {
    @HostBinding('attr.role') role = 'nav';
    @HostBinding('class.pressed') isPressed: boolean = true;

    @HostListener('click', ['$event.target'])
    onClick(elem: HTMLElement) {
        console.log(elem);
    }
}

queries - 視圖查詢

@Component({
    selector: 'demo-component',
    template: `
        <input #theInput type='text' />
        <div>Demo Component</div>
    `,
    queries: {
        theInput: new ViewChild('theInput')
    }
})
export class DemoComponent {
    theInput: ElementRef;
}

等價於:

@Component({
    selector: 'demo-component',
    template: `
        <input #theInput type='text' />
        <div>Demo Component</div>
    `
})
export class DemoComponent {
    @ViewChild('theInput') theInput: ElementRef;
}

queries - 內容查詢

<my-list>
    <li *ngFor="let item of items;">{{item}}</li>
</my-list>
@Directive({
    selector: 'li'
})
export class ListItem {}
@Component({
    selector: 'my-list',
    template: `
        <ul>
            <ng-content></ng-content>
        </ul>
    `,
    queries: {
        items: new ContentChild(ListItem)
    }
})
export class MyListComponent {
    items: QueryList<ListItem>;
}

等價於:

@Component({
    selector: 'my-list',
    template: `
        <ul>
            <ng-content></ng-content>
        </ul>
    `
})
export class MyListComponent {
    @ContentChild(ListItem) items: QueryList<ListItem>;
}

styleUrls、styles

  • styleUrls和styles允許同時指定。

  • 優先順序:模板內聯樣式 > styleUrls > styles。

  • 建議:使用styleUrls引用外部樣式表文件,這樣代碼結構相比styles更清晰、更易於管理。同理,模板推薦使用templateUrl引用模板文件。

changeDetection

  • ChangeDetectionStrategy.Default:組件的每次變化監測都會檢查其內部的所有數據(引用對象也會深度遍歷),以此得到前後的數據變化。

  • ChangeDetectionStrategy.OnPush:組件的變化監測只檢查輸入屬性(即@Input修飾的變數)的值是否發生變化,當這個值為引用類型(Object,Array等)時,則只對比該值的引用。

  • 顯然,OnPush策略相比Default降低了變化監測的複雜度,很好地提升了變化監測的性能。如果組件的更新只依賴輸入屬性的值,那麼在該組件上使用OnPush策略是一個很好的選擇。

encapsulation

  • ViewEncapsulation.None:無 Shadow DOM,並且也無樣式包裝。

  • ViewEncapsulation.Emulated:無 Shadow DOM,但是通過Angular提供的樣式包裝機制來模擬組件的獨立性,使得組件的樣式不受外部影響,這是Angular的預設設置。

  • ViewEncapsulation.Native:使用原生的 Shadow DOM 特性。

生命周期

當Angular使用構造函數新建組件後,就會按下麵的順序在特定時刻調用這些生命周期鉤子方法:

生命周期鉤子 調用時機
ngOnChanges 在ngOnInit之前調用,或者當組件輸入數據(通過@Input裝飾器顯式指定的那些變數)變化時調用。
ngOnInit 第一次ngOnChanges之後調用。建議此時獲取數據,不要在構造函數中獲取
ngDoCheck 每次變化監測發生時被調用。
ngAfterContentInit 使用
ngAfterContentChecked ngAfterContentInit後被調用,或者每次變化監測發生時被調用(只適用組件)。
ngAfterViewInit 創建了組件的視圖及其子視圖之後被調用(只適用組件)。
ngAfterViewChecked ngAfterViewInit,或者每次子組件變化監測時被調用(只適用組件)。
ngOnDestroy 銷毀指令/組件之前觸發。此時應將不會被垃圾回收器自動回收的資源(比如已訂閱的觀察者事件、綁定過的DOM事件、通過setTimeout或setInterval設置過的計時器等等)手動銷毀掉。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在ECMAscript中,變數可以存放兩種類型的值,即原始值和引用值 原始值指的是代表原始數據類型的值,也叫基本數據類型,包括:Number、Stirng、Boolean、Null、Underfined 引用值指的是複合數據類型的值,包括:Object、Function、Array、Date、Reg ...
  • Q:什麼情況下會碰到跨域問題?有哪些解決方法? 跨域問題是這是瀏覽器為了安全實施的同源策略導致的,同源策略限制了來自不同源的document、腳本,同源的意思就是兩個URL的功能變數名稱、協議、埠要完全相同。 script標簽jsonp跨域、nginx反向代理、node.js中間件代理跨域、後端在頭部信息 ...
  • 一、兩者的區別 相等:先強制轉換變數類型,再比較 全等:不轉換類型,一旦類型不同,就是不全等。 二、相等和不相等的比較規則 1.操作符中有布爾值時: 比較前先將之轉換為數值 false = 0 , true = 1 2.字元串,另一個是數值: 字元串去將就數值 3.對象: object.valueO ...
  • 賬單列印 Ι 收據列印 返回賬單列表 列印 ... ...
  • 我上一篇關於vue的文章和這一篇時間隔了有點久了。最近終於寫完了。 因為我一直想寫個有點實績的東西,而不是隨便寫一個教程一樣東西。結合最近在項目中學到的經驗和我的一點創意。 首先介紹下這是個什麼! H5直播平臺! 不是一個標題,我已經開發完了。 接著這裡是登錄註冊的流程圖 這邊微信登錄,因為沒有我個 ...
  • function smalltoBIG(n) { var fraction = ['角', '分']; var digit = ['零', '壹', '貳', '叄', '肆', '伍', '陸', '柒', '捌', '玖']; var unit = [ ['元', '萬', '億'... ...
  • function getYourString(s) { var res = ''; var length = s.length; for (var i = 0, j = 1; i '; } else { res += s[i]; } } ... ...
  • module.exports返回的是一個{}, expoerts是對module.exports的一個引用; 即: module.exports = { abc: ‘abc’ }; exports.hehe = ‘hehe’; 等價於: module.exports = { abc: ‘abc’, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...