1. 簡介
特約作者:Aayush Arora
Angular Elements 是封裝為自訂元素的 Angular 元件。目前 Chrome、Opera 和 Safari 支援這些 API,其他瀏覽器則可透過 Polyfill 使用。這些元素可運用整個 Angular 基礎架構,包括常見的 Angular 介面和變更偵測策略。註冊完成後,即可在瀏覽器中使用這些元素。
本程式碼研究室會逐步說明如何建立自己的圖片滑桿 Angular 元件,然後協助您將其轉換為 Angular 元素,以便在 Angular 架構外運作。
建構目標
在本程式碼研究室中,您將使用 Angular 建構圖片滑桿元素。您的元素 wi:
|
課程內容
- 如何製作圖片滑桿自訂元件
- 如何將圖片滑桿自訂元件轉換為自訂元素
- 如何封裝元件,使其可在瀏覽器中運作
軟硬體需求
- 最新版本的 angular-cli。
- 範例程式碼
- 文字編輯器
- 具備 Angular 元件的基本知識
本程式碼研究室著重於 Angular Elements。我們不會對與本主題無關的概念和程式碼多做介紹,但會事先準備好這些程式碼區塊,屆時您只要複製及貼上即可。
2. 開始設定
下載程式碼
點選下方連結即可下載這個程式碼研究室的所有程式碼:
將下載的 ZIP 檔案解壓縮。這會解壓縮根資料夾 (angular-element-codelab-master)
,其中包含
兩個資料夾 (image-slider)
和 (image-slider-finished)
。我們將在名為 image-slider 的目錄中完成所有編碼工作。
執行專案
如要執行專案,您需要在根目錄 ( image-slider) 中執行指令 ( ng-serve)。
應用程式完成啟動程序後,您會看到以下內容:
3. 製作 Image-Slider 自訂元件?
如何建立圖片輪播?
在這個圖片滑桿中,請使用 Angular 點擊繫結繫結按鈕。我們會建立物件陣列,內含圖片、替代標記、連結等。我們會將這些圖片依序放在容器中,並在點選時平移容器。
我們會建立圖片滑桿元件,然後將其轉換為 Angular 元素。
- 圖片和名稱的容器。
- 包含資料的陣列
- 繫結資料的範本
4. 實作圖片滑桿元件
您可以透過多種方式開始任何專案,但為了盡可能簡化專案並專注於 Angular 元素,我們提供基本程式碼和 CSS。
建立陣列和資料服務
請注意,sliderArray 會包含:
- 輪播圖片的圖片網址 img 鍵
- 提供圖片替代文字的 alt 標記
- 提供圖片說明的文字
src/assets
目錄中現有的 data.json
檔案應如下所示。
sliderArray = [
{img: 'http://bloquo.cc/img/works/1.jpg', alt: '', text: '365 Days Of weddings a year'},
{img: 'http://bloquo.cc/img/works/2.jpg', alt: '', text: '365 Days Of weddings a year'},
{img: 'http://bloquo.cc/img/works/3.jpg', alt: '', text: '365 Days Of weddings a year'},
{img: 'http://bloquo.cc/img/works/4.jpg', alt: '', text: '365 Days Of weddings a year'},
{img: 'http://bloquo.cc/img/works/5.jpg', alt: '', text: '365 Days Of weddings a year'}
];
我們需要使用服務在元件中擷取這項資料。在 data.service.ts
檔案中,我們將使用 @angular/common/http
中的 httpClient
模組編寫 getData()
方法,從上方建立的陣列擷取資料。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'
const URL = '../assets/data.json';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get(URL)
}
}
從資料服務擷取資料
我們需要在元件內匯入服務,然後訂閱可觀測值,從 data.json
取得物件
為此,我們需要執行三個步驟:
- 初始化元件陣列
- 訂閱
getData()
函式傳回的可觀察物件 - 建立 Result 介面,以便在訂閱可觀測項目後檢查資料型別。
- 將資料指派給元件陣列。
初始化元件陣列
我們會在 slider.component.ts
中宣告並初始化元件陣列,也就是物件陣列:
如要聲明:
sliderArray: object[];
如要初始化,請按照下列步驟操作:
constructor(private data: DataService) {
this.sliderArray = [];
}
接著,我們需要在建構函式中匯入及初始化服務
constructor(private data: DataService) {}
現在我們已準備好使用服務,並呼叫服務方法。
從資料服務取得資料
如要從服務中取得資料,請呼叫 getData()
方法並訂閱其傳回的可觀測項目,同時建立 Result,
介面,以便檢查我們是否取得正確的資料。
我們會在 ngOnInit
方法中執行這項操作:
this.data.getData().subscribe((result: Result)=>{
})
將資料指派給元件陣列
最後,我們會將資料指派給元件陣列:
this.data.getData().subscribe((result: Result)=>{
this.sliderArray = result.sliderArray;
})
將資料放入元件的陣列後,我們就能將範本與這項資料繫結。
在 slider.component.html,
中,我們已有 HTML 範本。下一步是將這個範本與 sliderArray
繫結。
5. 將資料繫結至範本
我們會使用 *ngFor
指令將資料繫結至範本,最後在範本中新增轉換,讓滑桿正常運作。
這包含三個步驟:
- 將
sliderArray
繫結至範本 - 為滑桿按鈕新增事件繫結
- 使用
ngStyle
和ngClass
新增 CSS 變形效果
將 slideArray 繫結至元件
我們有一個容器,其中包含 img-container
、a
text-container
和 a
slider.
我們會使用 *ngFor
指令,繫結所有三個容器中的資料
<div class="container">
<div class="img-container" *ngFor="let i of sliderArray; let select = index;">
<img src="{{i.img}}" alt="{{i.alt}}" >
</div>
<div>
<div class="text-container">
<div class="page-text" *ngFor="let i of sliderArray;let select = index;">
<h3>{{i.text}}</h3>
</div>
</div>
</div>
</div>
<div class="slider">
<div class="slide-button-parent-container" *ngFor="let i of sliderArray; let x =index">
<div class="select-box">
<div class="slide-button">
</div>
</div>
</div>
</div>
將事件繫結至 slideArray
資料繫結後,我們將使用 Angular click binding
將點擊事件繫結至每個滑桿按鈕。我們會建立名為 selected(x)
的函式,其中 x 是陣列的索引。
selected(x) {
this.downSelected(x);
this.selectedIndex = x;
}
downSelected(i) {
this.transform = 100 - (i) * 50;
this.selectedIndex = this.selectedIndex + 1;
if(this.selectedIndex > 4) {
this.selectedIndex = 0;
}
}
請注意以下幾點:
- 下選函式會將轉換屬性的值減少五十倍,索引會傳遞至
selected
函式。 - 這項邏輯會將文字容器平移 100%、50%、-50% 和 -100%,產生四種不同狀態。
使用 ngStyle 和 ngClass 新增 CSS 轉換
一開始,我們將所有圖片的不透明度設為零,當所選索引等於圖片索引時,我們會使用 ngClass directive
新增 selected
類別。這個 selected
類別會將圖片的不透明度設為 1,讓使用者看到圖片。
<div class="img-container" *ngFor="let i of sliderArray; let select = index;"
[ngClass]="{'selected': select == selectedIndex}">
</div>
接著,我們會根據使用 select()
函式計算出的 transform
值,翻譯文字容器。
<div [ngStyle]="{'transform': 'translateY('+ transform + '%' +')', 'transition': '.8s'}">
</div>
完成上述所有步驟後,您會看到最終程式碼,如下所示:
<div class="container">
<div class="img-container" *ngFor="let i of sliderArray; let select = index;"
[ngClass]="{'selected': select == selectedIndex}">
<img src="{{i.img}}" alt="{{i.alt}}" >
</div>
<!--</div>-->
<div [ngStyle]="{'transform': 'translateY('+ transform + '%' +')', 'transition': '.8s'}">
<div class="text-container">
<div class="page-text" *ngFor="let i of sliderArray;let select = index;" [ngClass]="{'selected': select == selectedIndex}">
<h3>{{i.text}}</h3>
</div>
</div>
</div>
</div>
<div class="slider">
<div class="slide-button-parent-container" *ngFor="let i of sliderArray; let x =index" (click)="selected(x)" >
<div class="select-box">
<div class="slide-button" [ngClass]="{'slide-button-select': x == selectedIndex}" >
</div>
</div>
</div>
</div>
6. 將元件轉換為 Angular 元素
這項程序包含五個步驟:
- 使用
Shadow DOM
處理角度元素 - 善用
entryComponents
- 從
@angular/elements
匯入及使用CreateCustomElement
模組 - 定義
custom-element
- 執行
ngDoBootstrap
方法
使用 Angular 元素的 Shadow DOM
現在圖片滑桿已可運作,我們只需要將其設為 Angular Element
。
有趣的是,只要稍做變更,就能將元件 DOM 變成 shadow DOM。
我們需要匯入 ViewEncapsulation
模組,並使用其中的 ShadowDom
方法。
@Component({
selector: 'app-slider',
templateUrl: './slider.component.html',
styleUrls: ['./slider.component.css'],
encapsulation: ViewEncapsulation.ShadowDom
})
善用 entryComponents
進入元件是 Angular 命令式載入的元件。您可以在 NgModule 中啟動項目元件,藉此指定項目元件。
在這裡,我們會在 @NgModule
內的 entryComponents
陣列中指定 SliderComponent
@NgModule({
declarations: [
SliderComponent
],
imports: [
BrowserModule,
HttpClientModule
]
})
匯入及使用 createCustomElement 模組
在這裡,我們需要使用 @angular/elements.
中的 createCustomElement
模組。您需要將 SliderComponent,
做為 createCustomElement
函式的參數。接著,我們需要在 DOM 中註冊 slider
。
import { createCustomElement } from '@angular/elements';
export class AppModule {
constructor(private injector: Injector) {
const slider = createCustomElement(SliderComponent, { injector });
}
}
如要將滑桿註冊為 DOM 元素,我們將使用 customElements.define
方法定義滑桿。
customElements.define('motley-slider', slider);
最後,我們必須使用 ngDoBootstrap()
方法啟動這個自訂元素。完整程式碼如下所示:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { SliderComponent } from './slider/slider.component';
import { HttpClientModule} from "@angular/common/http";
@NgModule({
declarations: [
SliderComponent
],
imports: [
BrowserModule,
HttpClientModule
]
})
export class AppModule {
constructor(private injector: Injector) {
const slider = createCustomElement(SliderComponent, { injector });
customElements.define('motley-slider', slider);
}
ngDoBootstrap() {}
}
封裝 Angular 元素
我們需要使用新指令修改 package.json
,因此請修改 package.json
檔案中的指令碼物件。
現在來檢查修改後的指令碼物件:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod --output-hashing=none",
"package": "cat dist/my-app/{runtime,polyfills,scripts,main}.js | gzip > elements.js.gz",
"serve": "http-server",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
現在我們可以執行 ng build & ng package
指令,最後執行 ng serve 來提供使用建構指令產生的 dist/ 資料夾。此外,我們可以使用從 ng package
指令取得的 gzip
,然後擷取並發布為 npm module
。