使用Angular 10 創建Web Component全解析


摘要:使用原生js,html,css封裝web component比較麻煩,在angular 10.0中,提供了一種使用angular elements把angular component轉換成web component的能力。

這是一篇介紹如何使用angular創建web component的文章。

你將會看到:

  1. 使用angular創建web component的原理

  2. 如何使用angular創建web component

    1. 新建angular工程

    2. 刪除app.component組件及更新app.module
    3. 安裝依賴包:angular custom elements

    4. 新建angular component

    5. 添加到entryComponent中

    6. 使用createCustomElement()函數創建自定義元素

    7. 使用customElements.define()函數把自定義元素掛載到瀏覽器上的customElementRestory

  3. 打包項目

  4. 優化打包過程

  5. 在原本的angular項目中使用

  6. 在其他angular項目中使用

  7. 在普通的html中使用

  8. 在react項目中使用

  9. 使用angular來封裝web component的一些問題
  10. 如何使用web component實現微前端

版本:

demo使用的是新版 angular 10.04版本。

一. 工作原理:

angular提供了createCustomElement()函數,它把angular component的各種功能轉換成web component標准的各種接口。

然后使用原生的customElements.define()函數把自定義的元素注冊到瀏覽器的CustomElementRegistry中。

這樣,當頁面上出現這個自定義的元素時,瀏覽器會把CustomElementRegistry中的相對應的元素實例化,實例化出的對象其實是使用angular component的語法,包括數據綁定和變更檢測。

 

二. 具體步驟:

1.新建angular工程:ng new custom-elements-demo

執行:ng new custom-elements-demo

 等待安裝包完成:

 看一下現在的目錄結構:

 

 項目初始化已經完成了。

 此處正常情況應該有嘆息的,畢竟安裝包需要挺長長長長時間的的的的~~~

2.刪除不必要的app.component

在原來的angular項目中,app.component是作為入口組件的,現在我們只是為了生成web component,就沒有必要有入口組件了。刪除與app.component相關的內容。

  • 刪除src/app/app.component.html

  • 刪除src/app/app.component.scss

  • 刪除src/app/app.component.ts

  • 刪除src/app/app.component.spec.ts

  • 更新src/app/app.module.ts

目錄結構:

 

 app.module.ts內容

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

@NgModule({
  declarations: [],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: []
})
export class AppModule { }

  

3.安裝依賴包:ng add @angular/elements

@angular/elements是angular自定義元素的工具包,我們來安裝一下。

執行:ng add @angular/elements

 

 

 可以看到,當你安裝@angular/elements,會默認安裝document-register-element膩子腳本,並且添加到src/polyfills.ts中。

那么為什么需要添加膩子腳本呢?原因是:目前不是所有瀏覽器都支持自定義元素的,要想讓不支持自定義元素的瀏覽器正常使用,需要添加膩子腳本。

我們來對比一下代碼:

 

 

 會安裝2個依賴:@angular/elements和document-register-element

 

 

 修改了src/polyfills.ts這個文件,添加膩子腳本到項目中。

4.新建angular component: ng g c custom-card

新建一個空的angular component

執行: ng g c custom-card

 完成custom-card組件,這里就直接貼一下代碼了。

custom-card.component.html

1 <span>{{name}}</span>
2 <div class="info">
3     <span>{{info.age}}</span>
4     <span>{{info.phone}}</span>
5 </div>
6 <button class="select" (click)="onSelectUser()">選擇用戶</button>

 

custom-card.component.scss

 1 :host {
 2     display: flex;
 3     flex-direction: column;
 4     width: 200px;
 5     height: 200px;
 6     border: 1px solid gray;
 7 
 8     padding: 20px;
 9     .info {
10         padding: 20px;
11         span {
12             display: block;
13         }
14     }
15 }

 

custom-card.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { UtilService } from '../util.service';
@Component({
  selector: 'app-custom-card',
  templateUrl: './custom-card.component.html',
  styleUrls: ['./custom-card.component.scss']
})
export class CustomCardComponent implements OnInit {
  @Input() name = '';
  @Input() info = {
    age: 0,
    phone: ''
  };
  @Output() selectUser = new EventEmitter();

  constructor(
    private util: UtilService
  ) { }
  ngOnInit(): void {
    this.util.log();
  }
  onSelectUser(): void {
    this.selectUser.emit({...this.info, name: this.name});
  }
}

 

這里card顯示user的name age phone,其中name是單獨作為字符串傳遞進card 組件的,而age 和 phone是包裝在info對象中的,只是為了演示傳遞值的區別。

當用戶點擊選擇user的button時,會把當前的user信息發送出來,這是為了演示怎么響應web component的事件。

5.添加到entryComponent

有一類組件被包含在模板中,它們是聲明式加載的;另一類組件你會命令式加載它,這就是入口組件。對於入口組件,需要添加到module.entryComponent中。

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CustomCardComponent } from './custom-card/custom-card.component';

@NgModule({
  declarations: [CustomCardComponent],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [],
  entryComponents: [CustomCardComponent]
})
export class AppModule { }

6.使用createCustomElement()函數創建自定義元素

@angular/elements包導出的createCustomElement()函數原來把angular component轉換成瀏覽器能夠識別的自定義元素。

const customCardEle = createCustomElement(CustomCardComponent, {injector});  

7.使用customElements.define()函數把自定義元素掛載到瀏覽器上的customElementRestory

customElements.define('custom-card', customCardEle);

 第一個參數是自定義元素的tag名稱,第2個參數就是自定義元素。

 

創建自定義元素的代碼放在哪里?

angular項目都需要有一個啟動組件,一般的angular項目定義在NgModule.bootstrap中,對於對於web component的組件,NgModule.bootstrap是空的。

這個時候,啟動組件其實是AppModule這個類中的ngDoBootstrap()函數,我們可以把定義web component的代碼放到這個函數中。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { CustomCardComponent } from './custom-card/custom-card.component';

@NgModule({
  declarations: [CustomCardComponent],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [],
  entryComponents: [CustomCardComponent]
})
export class AppModule {
  constructor(
    private injector: Injector
  ) {
  }
  ngDoBootstrap(): void {
    const customCardEle = createCustomElement(CustomCardComponent, {injector: this.injector});
    customElements.define('custom-card', customCardEle);
  }
}

  

 

至此,在angular中創建web component已經完成了,下面我們來看一下如何打包及使用。

三. 打包項目

1.執行:ng build --prod=true --outputHashing=none

  --prod=true可以讓angular優化打包的項目,例如 tree-shaking

  --outputHashing=none原本打包的文件名有hash值,使用這個設置可以去掉hash

 

 

 可以看到生成3個js文件,一個css文件。

我們新建一個html文件,把生成的runtime.js main.js polyfills.js和styles.css導入到這個html中。

test.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6     <title>Document</title>
 7     <style href="dist/custom-elements-demo/style.css"></style>
 8     <script src="dist/custom-elements-demo/main.js"></script>
 9     <script src="dist/custom-elements-demo/polyfills.js"></script>
10     <script src="dist/custom-elements-demo/runtime.js"></script>
11 </head>
12 <body>
13     <div>
14         <span>正被選擇的用戶:</span>
15         <span id="user"></span>
16     </div>
17     <custom-card id="1"></custom-card>
18     <custom-card id="2"></custom-card>
19     <script>
20         const user = document.getElementById('user');
21         const card = document.getElementById('1');
22         card.name = 'wt';
23         card.info = {age: 25, phone: '111-222-3333'};
24         card.addEventListener('selectUser', (e) => {
25             user.innerText = e.detail.name;
26         });
27         const card1 = document.getElementById('2');
28         card1.name = 'syc'
29         card1.info = {age: 18, phone: '555-666-3333'};
30         card1.addEventListener('selectUser', (e) => {
31             user.innerText = e.detail.name;
32         });
33     </script>
34 </body>
35 </html>

 

可以看到,custom-card這個web component的使用和一般的html元素並沒有區別。

下面是顯示的結果:

 

 我們可以看到,默認情況下,angular使用ng build是把項目打成4個文件的,3個js文件和一個css文件,一般的項目使用沒問題,但是定義web component項目,4個文件有點不方便,如果只使用一個文件就好了。

我們來使用webpack來再次打包一下,目標是合成一個文件。

 

 

 修改build 命令: ng build --prod=true --outputHashing=none --single-bundle


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM