国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Angular Elements 及其運作原理

qingshanli1988 / 1394人閱讀

摘要:以下是關于中一些模塊的概要以及它們與這篇文章的關聯性這個模塊實現了我們在這篇文章中討論的關于的幾個回調函數,同時它還會初始化一個策略類,這個類會作為連接和的橋梁。

現在,Angular Elements 這個項目已經在社區引起一定程度的討論。這是顯而易見的,因為 Angular Elements 提供了很多開箱即用的、十分強大的功能:

通過使用原生的 HTML 語法來使用 Angular Elements —— 這意味著不再需要了解 Angular 的相關知識

它是自啟動的,并且一切都可以按預期那樣運作

它符合 Web Components 規范,這意味著它可以在任何地方使用

雖然你沒有使用 Angular 開發整個網站,但你仍然可以從 Angular Framework 這個龐大的體系中收益

@angular/elements這個包提供可將 Angular 組件轉化為原生 Web Components 的功能,它基于瀏覽器的 Custom Elements API 實現。Angular Elements 提供一種更簡潔、對開發者更友善、更快樂地開發動態組件的方式 —— 在幕后它基于同樣的機制(指創建動態組件),但隱藏了許多樣板代碼。

關于如何通過 @angular/elements 創建一個 Custom Element,已經有大量的文章進行闡述,所以在這篇文章將深入一點,對它在 Angular 中的具體工作原理進行剖析。這也是我們開始研究 Angular Elements 的一系列文章的原因,我們將在其中詳細解釋 Angular 如何在 Angular Elements 的幫助下實現 Custom Elements API。

Custom Elements(自定義元素)

要了解更多關于 Custom Elements 的知識,可以通過 developers.google 中的這篇文章進行學習,文章詳細介紹了與 Custom Elements API 相關的內容。

這里針對 Custom Elements,我們使用一句話來概括:

使用 Custom Elements,web 開發者可以創建一個新的 HTML 標簽、增加已有的 HTML 標簽以及繼承其他開發者所開發的組件。
原生 Custom Elements

讓我們來看看下面的例子,我們想要創建一個擁有 name 屬性的 app-hello HTML 標簽。可以通過 Custom Elements API 來完成這件事。在文章的后續章節,我們將演示如何使用 Angular 組件的 @Input 裝飾器與 這個 name 屬性保持同步。但是現在,我們不需要使用 Angular Elements 或者 ShadowDom 或者使用任何關于 Angular 的東西來創建一個 Custom Element,我們僅使用原生的 Custom Components API。

首先,這是我們的 HTML 標記:

要實現一個 Custom Element,我們需要分別實現如下在標準中定義的 hooks:

callback summary
constructor 如果需要的話,可在其中初始化 state 或者 shadowRoot,在這篇文章中,我們不需要
connectedCallback 在元素被添加到 DOM 中時會被調用,我們將在這個 hook 中初始化我們的 DOM 結構和事件監聽器
disconnectedCallback 在元素從 DOM 中被移除時被調用,我們將在這個 hook 中清除我們的 DOM 結構和事件監聽器
attributeChangedCallback 在元素屬性變化時被調用,我們將在這個 hook 中更新我們內部的 dom 元素或者基于屬性改變后的狀態

如下是我們關于 Hello Custom Element 的實現代碼:

class AppHello extends HTMLElement {
  constructor() {
    super();
  }
  // 這里定義了那些需要被觀察的屬性,當這些屬性改變時,attributeChangedCallback 這個 hook 會被觸發
  static get observedAttributes() {return ["name"]; }

  // getter to do a attribute -> property reflection
  get name() {
    return this.getAttribute("name");
  }

  // setter to do a property -> attribute reflection
  // 通過 setter 來完成類屬性到元素屬性的映射操作
  set name(val) {
    this.setAttribute("name", val);
  }

  connectedCallback() {
    this.div = document.createElement("div");
    this.text = document.createTextNode(this.name || "");
    this.div.appendChild(this.text);
    this.appendChild(this.div);
  }

  disconnectedCallback() {
    this.removeChild(this.div);
  }

  attributeChangedCallback(attrName, oldVal, newVal) {
    if (attrName === "name" && this.text) {
      this.text.textContent = newVal;
    }
  }
}

customElements.define("hello-elem", AppHello);

這里是可運行實例的鏈接。這樣我們就實現了第一版的 Custom Element,回顧一下,這個 app-hellp 標簽包含一個文本節點,并且這個節點將會渲染通過 app-hello 標簽 name 屬性傳遞進來的任何內容,這一切僅僅基于原生 javascript。

將 Angular 組件導出為 Custom Element

既然我們已經了解了關于實現一個 HTML Custom Element 所涉及的內容,讓我們來使用 Angular實現一個相同功能的組件,之后再使它成為一個可用的 Custom Element。

首先,讓我們從一個簡單的 Angular 組件開始:

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

@Component({
  selector: "app-hello",
  template: `
{{name}}
` }) export class HelloComponent { @Input() name: string; }

正如你所見,它和上面的例子在功能上一模一樣。

現在,要將這個組件包裝為一個 Custom Element,我們需要創建一個 wrapper class 并實現所有 Custom Elements 中定義的 hooks:

class HelloComponentClass extends HTMLElement {
  constructor() {
    super();
  }

  static get observedAttributes() {
  }

  connectedCallback() {
  }

  disconnectedCallback() {
  }

  attributeChangedCallback(attrName, oldVal, newVal) {
  }
}

下一步,我們要做的是橋接 HelloComponentHelloComponentClass。它們之間的橋會將 Angular Component 和 Custom Element 連接起來,如圖所示:

要完成這座橋,讓我們來依次實現 Custom Elements API 中所要求的每個方法,并在這個方法中編寫關于綁定 Angular 的代碼:

callback summary angular part
constructor 初始化內部狀態 進行一些準備工作
connectedCallback 初始化視圖、事件監聽器 加載 Angular 組件
disconnectedCallback 清除視圖、事件監聽器 注銷 Angular 組件
attributeChangedCallback 處理屬性變化 處理 @Input 變化
1. constructor()

我們需要在 connectedCallback() 方法中初始化 HelloComponent,但是在這之前,我們需要在 constructor 方法中進行一些準備工作。

順便,關于如何動態構造 Angular 組件可以通過閱讀Dynamic Components in Angular這篇文章進行了解。它其中闡述的運作機制和我們這里使用的一模一樣。

所以,要讓我們的 Angular 動態組件能夠正常工作(需要 componentFactory 能夠被編譯),我們需要將 HelloComponent 添加到 NgModuleentryComponents 屬性(它是一個列表)中去:

@NgModule({
  imports: [
    BrowserModule
  ],
  declarations: [HelloComponent],
  entryComponents: [HelloComponent]
})
export class CustomElementsModule {
  ngDoBootstrap() {}
}

基本上,調用 prepare() 方法會完成兩件事:

它會基于組件的定義初始化一個 factoryComponent 工廠方法

它會基于 Angular 組件的 inputs 初始化 observedAttributes,以便我們在 attributeChangedCallback() 中完成我們需要做的事

class AngularCustomElementBridge {
  prepare(injector, component) {
    this.componentFactory = injector.get(ComponentFactoryResolver).resolveComponentFactory(component);

    // 我們使用 templateName 來處理 @Input("aliasName") 這種情形
    this.observedAttributes = componentFactory.inputs.map(input => input.templateName); 
  }
}
2. connectedCallback()

在這個回調函數中,我們將看到:

初始化我們的 Angular 組件(就如創建動態組件那樣)

設置組件的初始 input 值

在渲染組件時,觸發臟檢查機制

最后,將 HostView 增加到 ApplicationRef

如下是實戰代碼:

class AngularCustomElementBridge {
  initComponent(element: HTMLElement) {
    // 首先我們需要 componentInjector 來初始化組件
    // 這里的 injector 是 Custom Element 外部的注入器實例,調用者可以在這個實例中注冊
    // 他們自己的 providers
    const componentInjector = Injector.create([], this.injector);
  
    this.componentRef = this.componentFactory.create(componentInjector, null, element);

    // 然后我們要檢查是否需要初始化組件的 input 的值
    // 在本例中,在 Angular Element 被加載之前,user 可能已經設置了元素的屬性
    // 這些值被保存在 initialInputValues 這個 map 結構中
    this.componentFactory.inputs.forEach(prop => this.componentRef.instance[prop.propName] = this.initialInputValues[prop.propName]);

    // 之后我們會觸發臟檢查,這樣組件在事件循環的下一個周期會被渲染
    this.changeDetectorRef.detectChanges();
    this.applicationRef = this.injector.get(ApplicationRef);

    // 最后,我們使用 attachView 方法將組件的 HostView 添加到 applicationRef 中
    this.applicationRef.attachView(this.componentRef.hostView);
  }
}
3. disconnectedCallback()

這個十分容易,我們僅需要在其中注銷 componentRef 即可:

class AngularCustomElementBridge {
  destroy() {
    this.componentRef.destroy();
  }
}
4. attributeChangedCallback()

當元素屬性發生改變時,我們需要相應地更新 Angular 組件并觸發臟檢查:

class AngularCustomElementBridge {
  setInputValue(propName, value) {
    if (!this.componentRef) {
      this.initialInputValues[propName] = value;
      return;
    }
    if (this.componentRef[propName] === value) {
      return;
    }
    this.componentRef[propName] = value;
    this.changeDetectorRef.detectChanges();
  }
}
5. Finally, we register the Custom Element
customElements.define("hello-elem", HelloComponentClass);

這是一個可運行的例子鏈接。

總結

這就是根本思想。通過在 Angular 中使用動態組件,我們簡單實現了 Angular Elements 所提供的基礎功能,重要的是,沒有使用 @angular/element 這個庫。

當然,不要誤解 —— Angular Elements 的功能十分強大。文章中所涉及的所有實現邏輯在 Angular Elements 都已被抽象化,使用這個庫可以使我們的代碼更優雅,可讀性和維護性也更好,同時也更易于擴展。

以下是關于 Angular Elements 中一些模塊的概要以及它們與這篇文章的關聯性:

create-custom-element.ts:這個模塊實現了我們在這篇文章中討論的關于 Custom Element 的幾個回調函數,同時它還會初始化一個 NgElementStrategy 策略類,這個類會作為連接 Angular Component 和 Custom Elements 的橋梁。當前,我們僅有一個策略 —— component-factory-strategy.ts —— 它的運作機制與本文例子中演示的大同小異。在將來,我們可能會有其他策略,并且我們還可以實現自定義策略。

component-factory-strategy.ts:這個模塊使用一個 component 工廠函數來創建和銷毀組件引用。同時它還會在 input 改變時觸發臟檢查。這個運作過程在上文的例子中也有被提及。

下次我們將闡述 Angular Elements 通過 Custom Events 輸出事件。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/96167.html

相關文章

  • 【教學向】150行代碼教你實現一個低配版的MVVM庫(2)- 代碼篇

    摘要:也放出地址,上面有完整工程以及在線演示地址相關閱讀教學向行代碼教你實現一個低配版的庫原理篇教學向行代碼教你實現一個低配版的庫代碼篇教學向再加行代碼教你實現一個低配版的庫設計篇教學向再加行代碼教你實現一個低配版的庫原理篇 書接上一篇: 150行代碼教你實現一個低配版的MVVM庫(1)- 原理篇 寫在前面 為了便于分模塊,和閱讀,我使用了Typescript來進行coding,總行數是正好...

    loonggg 評論0 收藏0
  • “別更新了,學不動了” 之:全棧開發者 2019 應該學些什么?

    摘要:但是,有一件事是肯定的年對全棧開發者的需求量很大。有一些方法可以解決這個問題,例如模式,或者你可以這么想,其實谷歌機器人在抓取單頁應用程序時沒有那么糟糕。谷歌正在這方面努力推進,但不要指望在年會看到任何突破。 對于什么是全棧開發者并沒有一個明確的定義。但是,有一件事是肯定的:2019 年對全棧開發者的需求量很大。在本文中,我將向你概述一些趨勢,你可以嘗試根據這些趨勢來確定你可能要投入的...

    NervosNetwork 評論0 收藏0
  • “別更新了,學不動了” 之:全棧開發者 2019 應該學些什么?

    摘要:但是,有一件事是肯定的年對全棧開發者的需求量很大。有一些方法可以解決這個問題,例如模式,或者你可以這么想,其實谷歌機器人在抓取單頁應用程序時沒有那么糟糕。谷歌正在這方面努力推進,但不要指望在年會看到任何突破。 對于什么是全棧開發者并沒有一個明確的定義。但是,有一件事是肯定的:2019 年對全棧開發者的需求量很大。在本文中,我將向你概述一些趨勢,你可以嘗試根據這些趨勢來確定你可能要投入的...

    sutaking 評論0 收藏0
  • “別更新了,學不動了” 之:全棧開發者 2019 應該學些什么?

    摘要:但是,有一件事是肯定的年對全棧開發者的需求量很大。有一些方法可以解決這個問題,例如模式,或者你可以這么想,其實谷歌機器人在抓取單頁應用程序時沒有那么糟糕。谷歌正在這方面努力推進,但不要指望在年會看到任何突破。 對于什么是全棧開發者并沒有一個明確的定義。但是,有一件事是肯定的:2019 年對全棧開發者的需求量很大。在本文中,我將向你概述一些趨勢,你可以嘗試根據這些趨勢來確定你可能要投入的...

    ormsf 評論0 收藏0
  • 精讀《JS 引擎基礎之 Shapes and Inline Caches》

    摘要:概述的解釋器優化器代碼可能在字節碼或者優化后的機器碼狀態下執行,而生成字節碼速度很快,而生成機器碼就要慢一些了。比如有一個函數,從獲取值引擎生成的字節碼結構是這樣的指令是獲取參數指向的對象,并存儲在,第二步則返回。 1 引言 本期精讀的文章是:JS 引擎基礎之 Shapes and Inline Caches 一起了解下 JS 引擎是如何運作的吧! JS 的運作機制可以分為 AST 分...

    Tecode 評論0 收藏0

發表評論

0條評論

qingshanli1988

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<