1. บทนำ
โดยผู้เขียนรับเชิญ Aayush Arora
Angular Elements คือคอมโพเนนต์ Angular ที่จัดแพ็กเกจเป็นองค์ประกอบที่กำหนดเอง ปัจจุบัน Chrome, Opera และ Safari รองรับการใช้งานฟีเจอร์นี้ และเบราว์เซอร์อื่นๆ จะใช้งานได้ผ่าน Polyfill องค์ประกอบเหล่านี้สามารถใช้โครงสร้างพื้นฐานทั้งหมดของ Angular ด้วยอินเทอร์เฟซ Angular ทั่วไปและกลยุทธ์การตรวจหาการเปลี่ยนแปลง เมื่อลงทะเบียนแล้ว คุณจะใช้องค์ประกอบเหล่านี้ภายในเบราว์เซอร์ได้
Codelab นี้จะแนะนำวิธีสร้างคอมโพเนนต์ Angular แถบเลื่อนรูปภาพของคุณเอง จากนั้นจะช่วยคุณเปลี่ยนให้เป็นองค์ประกอบ Angular เพื่อให้ทำงานนอกเฟรมเวิร์ก Angular ได้
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้สร้างองค์ประกอบแถบเลื่อนรูปภาพโดยใช้ Angular องค์ประกอบของคุณ wi:
|
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างคอมโพเนนต์ที่กำหนดเองของแถบเลื่อนรูปภาพ
- วิธีเปลี่ยนคอมโพเนนต์ที่กำหนดเองของแถบเลื่อนรูปภาพเป็นองค์ประกอบที่กำหนดเอง
- วิธีแพ็กเกจคอมโพเนนต์เพื่อให้ทำงานภายในเบราว์เซอร์ได้
สิ่งที่ต้องมี
- angular-cli เวอร์ชันล่าสุด
- โค้ดตัวอย่าง
- โปรแกรมแก้ไขข้อความ
- ความรู้พื้นฐานเกี่ยวกับคอมโพเนนต์ Angular
Codelab นี้มุ่งเน้นที่ Angular Elements เราจะข้ามแนวคิดและบล็อกโค้ดที่ไม่เกี่ยวข้องไป และจะให้คุณคัดลอกและวางได้ง่ายๆ
2. การเริ่มตั้งค่า
ดาวน์โหลดโค้ด
คลิกลิงก์ต่อไปนี้เพื่อดาวน์โหลดโค้ดทั้งหมดสำหรับ Codelab นี้
คลายไฟล์ ZIP ที่ดาวน์โหลด การดำเนินการนี้จะแตกโฟลเดอร์รูท (angular-element-codelab-master)
ซึ่งมีรายการต่อไปนี้
โฟลเดอร์ 2 โฟลเดอร์ ได้แก่ (image-slider)
และ (image-slider-finished)
เราจะทำงานด้านการเขียนโค้ดทั้งหมดในไดเรกทอรีที่ชื่อว่า image-slider
การดำเนินโครงการ
หากต้องการเรียกใช้โปรเจ็กต์ คุณต้องเรียกใช้คำสั่ง ( ng-serve) จากไดเรกทอรีราก ( image-slider)
เมื่อแอปเริ่มต้นแล้ว คุณจะเห็นสิ่งต่อไปนี้
3. การสร้างคอมโพเนนต์ที่กำหนดเองของ Image-Slider
วิธีสร้างแถบเลื่อนรูปภาพ
สำหรับแถบเลื่อนรูปภาพนี้ ให้เชื่อมโยงปุ่มโดยใช้การเชื่อมโยงการคลิกเชิงมุม เราจะสร้างอาร์เรย์ของออบเจ็กต์ที่มีรูปภาพ แท็ก Alt ลิงก์ ฯลฯ เราจะวางรูปภาพเหล่านี้ต่อกันในคอนเทนเนอร์และแปลคอนเทนเนอร์เมื่อคลิก
เราจะสร้างคอมโพเนนต์แถบเลื่อนรูปภาพ แล้วแปลงเป็น Angular Element
- คอนเทนเนอร์สำหรับรูปภาพและชื่อ
- อาร์เรย์ที่มีข้อมูล
- เทมเพลตเพื่อเชื่อมโยงข้อมูล
4. ใช้คอมโพเนนต์แถบเลื่อนรูปภาพ
คุณเริ่มโปรเจ็กต์ได้หลายวิธี ในกรณีนี้ เราได้ให้โค้ดพื้นฐานพร้อมกับ CSS เพื่อให้โปรเจ็กต์ของเราเรียบง่ายที่สุดและมุ่งเน้นไปที่ Angular Elements
การสร้างอาร์เรย์และบริการข้อมูล
อย่าลืมว่า sliderArray จะมีข้อมูลต่อไปนี้
- คีย์ img สำหรับ URL ของรูปภาพในแถบเลื่อน
- แท็ก alt เพื่อระบุข้อความแสดงแทนสำหรับรูปภาพ
- ข้อความที่ใช้ระบุคำอธิบายเกี่ยวกับรูปภาพ
ไฟล์ data.json
ที่อยู่ในไดเรกทอรี src/assets
อยู่แล้วควรมีลักษณะดังนี้
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
เราจะเขียนเมธอด getData()
โดยใช้โมดูล httpClient
จาก @angular/common/http
ซึ่งจะดึงข้อมูลจากอาร์เรย์ที่เราสร้างไว้ข้างต้น
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)
}
}
ดึงข้อมูลจากบริการข้อมูล
เราต้องนำเข้าบริการภายในคอมโพเนนต์ จากนั้นจึงจะสมัครใช้บริการ Observable เพื่อรับออบเจ็กต์จาก data.json
ได้
เราต้องทำตาม 3 ขั้นตอนต่อไปนี้
- การเริ่มต้นอาร์เรย์คอมโพเนนต์
- การติดตาม Observable ที่ฟังก์ชัน
getData()
แสดงผล - สร้างอินเทอร์เฟซ Result สำหรับการตรวจสอบประเภทของข้อมูลหลังจากสมัครใช้บริการ Observable
- กำหนดข้อมูลให้กับอาร์เรย์คอมโพเนนต์
กำลังเริ่มต้นอาร์เรย์คอมโพเนนต์
เราจะประกาศและเริ่มต้นอาร์เรย์คอมโพเนนต์ภายใน slider.component.ts
ซึ่งเป็นอาร์เรย์ของออบเจ็กต์
วิธีประกาศ
sliderArray: object[];
วิธีเริ่มต้น
constructor(private data: DataService) {
this.sliderArray = [];
}
จากนั้นเราต้องนำเข้าและเริ่มต้นบริการภายในเครื่องมือสร้าง
constructor(private data: DataService) {}
ตอนนี้เราพร้อมที่จะใช้บริการและเรียกใช้เมธอดของบริการแล้ว
การรับข้อมูลจากบริการข้อมูล
หากต้องการนำข้อมูลออกจากบริการ เราจะเรียกใช้เมธอด getData()
และติดตาม Observable ที่เมธอดจะส่งคืน นอกจากนี้ เราจะสร้างอินเทอร์เฟซ 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
Directive และสุดท้ายจะเพิ่มการเปลี่ยนรูปแบบในเทมเพลตเพื่อให้แถบเลื่อนทำงานได้
ซึ่งมี 3 ขั้นตอน ได้แก่
- การเชื่อมโยง
sliderArray
กับเทมเพลต - การเพิ่มการเชื่อมโยงเหตุการณ์สำหรับปุ่มแถบเลื่อน
- การเพิ่มการเปลี่ยนรูปแบบ CSS โดยใช้
ngStyle
และngClass
การเชื่อมโยง slideArray กับคอมโพเนนต์
เรามีคอนเทนเนอร์ที่มี img-container
, a
text-container
และ a
slider.
เราจะเชื่อมโยงข้อมูลในคอนเทนเนอร์ทั้ง 3 รายการโดยใช้คำสั่ง *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
เมื่อผูกข้อมูลแล้ว เราจะผูกเหตุการณ์คลิกกับปุ่มสไลด์ทุกปุ่มโดยใช้ click binding
ของ Angular เราจะสร้างฟังก์ชันที่ชื่อ 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;
}
}
ข้อควรทราบมีดังนี้
- ฟังก์ชันที่เลือกจะลดค่าของพร็อพเพอร์ตี้การเปลี่ยนรูป 50 เท่าของดัชนีที่ส่งผ่านเมื่อคลิกฟังก์ชัน
selected
- ตรรกะนี้จะแปลคอนเทนเนอร์ข้อความเป็น 100%, 50%, -50%, -100% ซึ่งส่งผลให้เกิดสถานะที่แตกต่างกัน 4 สถานะ
การเพิ่มการเปลี่ยนรูปแบบ CSS โดยใช้ ngStyle และ ngClass
ในตอนแรก เราตั้งค่ารูปภาพทั้งหมดให้มีความทึบแสงเป็น 0 จากนั้นเพิ่มคลาส selected
โดยใช้ ngClass directive
เมื่อดัชนีที่เลือกเท่ากับดัชนีรูปภาพ selected
คลาสนี้จะเพิ่มความทึบแสงเป็น 1 ให้กับรูปภาพเพื่อให้ผู้ใช้เห็นรูปภาพ
<div class="img-container" *ngFor="let i of sliderArray; let select = index;"
[ngClass]="{'selected': select == selectedIndex}">
</div>
หลังจากนี้ เราจะแปลคอนเทนเนอร์ข้อความตามค่า transform
ที่คำนวณโดยใช้ฟังก์ชัน select()
<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
กระบวนการนี้มี 5 ขั้นตอนดังนี้
- การใช้
Shadow DOM
สำหรับ Angular Element - การใช้ประโยชน์จาก
entryComponents
- การนำเข้าและใช้โมดูล
CreateCustomElement
จาก@angular/elements
- การกำหนด
custom-element
- วิธีการ
ngDoBootstrap
เรียกใช้
การใช้ Shadow DOM สำหรับองค์ประกอบ Angular
ตอนนี้เรามีแถบเลื่อนรูปภาพที่ทำงานอยู่แล้ว สิ่งที่เราต้องทำก็คือเปลี่ยนให้เป็น Angular Element
ส่วนที่น่าสนใจคือการเปลี่ยนแปลงเล็กๆ น้อยๆ ในการสร้าง DOM ของคอมโพเนนต์ ซึ่งก็คือ Shadow DOM
เราต้องนำเข้าโมดูล ViewEncapsulation
และต้องใช้วิธี ShadowDom
จากโมดูลดังกล่าว
@Component({
selector: 'app-slider',
templateUrl: './slider.component.html',
styleUrls: ['./slider.component.css'],
encapsulation: ViewEncapsulation.ShadowDom
})
การใช้ประโยชน์จาก entryComponents
Entry Component คือคอมโพเนนต์ที่ Angular โหลดโดยใช้คำสั่ง คุณระบุคอมโพเนนต์รายการโดยการเริ่มต้นใน NgModule
ในที่นี้ เราจะระบุ SliderComponent
ในอาร์เรย์ entryComponents
ภายใน @NgModule
@NgModule({
declarations: [
SliderComponent
],
imports: [
BrowserModule,
HttpClientModule
]
})
การนำเข้าและใช้โมดูล createCustomElement
ในที่นี้ เราต้องใช้โมดูล createCustomElement
จาก @angular/elements.
คุณต้องใช้ SliderComponent,
เป็นพารามิเตอร์ของฟังก์ชัน createCustomElement
หลังจากนั้น เราต้องลงทะเบียน slider
ใน DOM
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 Element
เราต้องแก้ไข 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/ ที่สร้างขึ้นโดยใช้คำสั่ง build นอกจากนี้ เรายังใช้ gzip
ที่ได้จากคำสั่ง ng package
แยกข้อมูล และเผยแพร่เป็น npm module
ได้ด้วย