使用 Angular 建構圖片滑桿元素

1. 簡介

特約作者:Aayush Arora

Angular Elements 是封裝為自訂元素的 Angular 元件。目前 Chrome、Opera 和 Safari 支援這些 API,其他瀏覽器則可透過 Polyfill 使用。這些元素可運用整個 Angular 基礎架構,包括常見的 Angular 介面和變更偵測策略。註冊完成後,即可在瀏覽器中使用這些元素。

本程式碼研究室會逐步說明如何建立自己的圖片滑桿 Angular 元件,然後協助您將其轉換為 Angular 元素,以便在 Angular 架構外運作。

建構目標

在本程式碼研究室中,您將使用 Angular 建構圖片滑桿元素。您的元素 wi:

  • 在瀏覽器中像 HTML 元素一樣運作
  • 可插入與 DOM 通訊的任何架構。

課程內容

  • 如何製作圖片滑桿自訂元件
  • 如何將圖片滑桿自訂元件轉換為自訂元素
  • 如何封裝元件,使其可在瀏覽器中運作

軟硬體需求

本程式碼研究室著重於 Angular Elements。我們不會對與本主題無關的概念和程式碼多做介紹,但會事先準備好這些程式碼區塊,屆時您只要複製及貼上即可。

2. 開始設定

下載程式碼

點選下方連結即可下載這個程式碼研究室的所有程式碼:

將下載的 ZIP 檔案解壓縮。這會解壓縮根資料夾 (angular-element-codelab-master),其中包含

兩個資料夾 (image-slider)(image-slider-finished)。我們將在名為 image-slider 的目錄中完成所有編碼工作。

執行專案

如要執行專案,您需要在根目錄 ( image-slider) 中執行指令 ( ng-serve)。

應用程式完成啟動程序後,您會看到以下內容:

19ffd082e2f024a5.png

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 繫結至範本
  • 為滑桿按鈕新增事件繫結
  • 使用 ngStylengClass 新增 CSS 變形效果

將 slideArray 繫結至元件

我們有一個容器,其中包含 img-containera text-containera 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