1. Giới thiệu
Do tác giả khách Aayush Arora
Angular Elements là các thành phần Angular được đóng gói dưới dạng các phần tử tuỳ chỉnh. Các API này hiện được Chrome, Opera và Safari hỗ trợ, đồng thời có sẵn trong các trình duyệt khác thông qua polyfill. Các phần tử này có thể sử dụng toàn bộ Cơ sở hạ tầng Angular với Giao diện Angular chung và Chiến lược phát hiện thay đổi. Sau khi đăng ký, bạn có thể sử dụng các phần tử này trong trình duyệt.
Lớp học lập trình này sẽ hướng dẫn bạn tạo thành phần Angular của riêng thanh trượt hình ảnh, sau đó giúp bạn chuyển đổi thành phần đó thành một phần tử Angular để có thể hoạt động bên ngoài Khung Angular.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ tạo một phần tử trình chiếu hình ảnh bằng Angular. Your element wi:
|
Kiến thức bạn sẽ học được
- Cách tạo thành phần tuỳ chỉnh cho trình chiếu hình ảnh
- Cách chuyển đổi thành phần tuỳ chỉnh image-slider thành phần tử tuỳ chỉnh
- Cách đóng gói thành phần để thành phần hoạt động trong trình duyệt
Bạn cần có
- Một phiên bản gần đây của angular-cli.
- Mã mẫu
- Trình chỉnh sửa văn bản
- Kiến thức cơ bản về Thành phần Angular
Lớp học lập trình này tập trung vào Angular Elements. Các khái niệm và khối mã không liên quan được tinh chỉnh và cung cấp cho bạn, chỉ cần sao chép và dán.
2. Chuẩn bị
Tải mã nguồn xuống
Nhấp vào đường liên kết sau đây để tải toàn bộ mã nguồn cho lớp học lập trình này:
Giải nén tệp zip đã tải xuống. Thao tác này sẽ giải nén một thư mục gốc (angular-element-codelab-master)
chứa
hai thư mục (image-slider)
và (image-slider-finished)
. Chúng ta sẽ thực hiện tất cả công việc lập trình trong một thư mục có tên là image-slider.
Chạy dự án
Để chạy dự án, bạn cần chạy lệnh ( ng-serve ) từ thư mục gốc ( image-slider ).
Sau khi ứng dụng được khởi động, bạn sẽ thấy:
3. Bạn muốn tạo một thành phần tuỳ chỉnh Image-Slider (Thanh trượt hình ảnh)?
Làm cách nào để tạo một thanh trượt hình ảnh?
Đối với trình chiếu hình ảnh này, hãy liên kết các nút bằng cách sử dụng tính năng liên kết lượt nhấp của Angular. Chúng ta sẽ tạo một mảng các đối tượng chứa hình ảnh, thẻ alt, đường liên kết, v.v. Chúng ta sẽ đặt các hình ảnh này bên dưới nhau trong một vùng chứa và dịch vùng chứa khi nhấp vào.
Chúng ta sẽ tạo một thành phần thanh trượt hình ảnh rồi chuyển đổi thành phần đó thành angular-element.
- Vùng chứa hình ảnh và tiêu đề.
- Một mảng chứa dữ liệu
- Mẫu để liên kết dữ liệu
4. Triển khai thành phần thanh trượt hình ảnh
Có nhiều cách để bắt đầu với bất kỳ dự án nào. Trong trường hợp này, để dự án của chúng ta đơn giản nhất có thể và tập trung vào Angular Elements, chúng tôi đã cung cấp cho bạn mã cơ bản cùng với css.
Tạo mảng và dịch vụ dữ liệu
Hãy nhớ rằng sliderArray sẽ chứa:
- Khoá img cho URL hình ảnh trong thanh trượt
- Thẻ alt để cung cấp văn bản thay thế cho hình ảnh
- Văn bản mô tả về hình ảnh
Tệp data.json
đã có trong thư mục src/assets
sẽ có dạng như sau.
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'}
];
Chúng ta cần tìm nạp dữ liệu này trong thành phần bằng cách sử dụng một dịch vụ. Trong tệp data.service.ts
, chúng ta sẽ viết một phương thức getData()
bằng cách sử dụng mô-đun httpClient
từ @angular/common/http
. Phương thức này sẽ tìm nạp dữ liệu từ mảng mà chúng ta đã tạo ở trên.
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)
}
}
Tìm nạp dữ liệu từ dịch vụ dữ liệu
Chúng ta cần nhập dịch vụ vào trong thành phần, sau đó có thể đăng ký theo dõi đối tượng có thể quan sát để lấy đối tượng từ data.json
Chúng ta cần thực hiện 3 bước cho việc này:
- Khởi tạo một mảng thành phần
- Đăng ký đối tượng có thể quan sát do hàm
getData()
trả về - Tạo một giao diện Result để kiểm tra loại dữ liệu sau khi đăng ký observable.
- Chỉ định dữ liệu cho mảng thành phần.
Khởi chạy mảng thành phần
Chúng ta sẽ khai báo và khởi tạo mảng thành phần bên trong slider.component.ts
. Đây là một mảng gồm các đối tượng:
Cách khai báo:
sliderArray: object[];
Cách khởi chạy:
constructor(private data: DataService) {
this.sliderArray = [];
}
Tiếp theo, chúng ta cần nhập và khởi động dịch vụ trong hàm khởi tạo
constructor(private data: DataService) {}
Giờ đây, chúng ta đã sẵn sàng sử dụng dịch vụ và gọi các phương thức dịch vụ.
Lấy dữ liệu từ Dịch vụ dữ liệu
Để lấy dữ liệu từ dịch vụ, chúng ta sẽ gọi phương thức getData()
và đăng ký với đối tượng có thể quan sát mà phương thức này sẽ trả về. Chúng ta cũng sẽ tạo một giao diện Result,
để có thể kiểm tra loại mà chúng ta đang nhận được dữ liệu chính xác.
Chúng ta sẽ thực hiện việc này trong phương thức ngOnInit
:
this.data.getData().subscribe((result: Result)=>{
})
Chỉ định dữ liệu cho Mảng thành phần
Cuối cùng, chúng ta sẽ chỉ định dữ liệu cho mảng thành phần:
this.data.getData().subscribe((result: Result)=>{
this.sliderArray = result.sliderArray;
})
Sau khi nhận được dữ liệu trong mảng của thành phần, chúng ta có thể liên kết mẫu với dữ liệu này.
Trong slider.component.html,
, chúng ta đã có một mẫu HTML. Bước tiếp theo là liên kết mẫu này với sliderArray
.
5. Liên kết dữ liệu với mẫu
Chúng ta sẽ liên kết dữ liệu với mẫu bằng cách sử dụng Chỉ thị *ngFor
và cuối cùng, chúng ta sẽ thêm các phép biến đổi vào mẫu để thanh trượt hoạt động.
Quy trình này gồm 3 bước:
- Liên kết
sliderArray
với mẫu - Thêm tính năng Liên kết sự kiện cho các nút thanh trượt
- Thêm các phép biến đổi CSS bằng cách sử dụng
ngStyle
vàngClass
Liên kết slideArray với Thành phần
Chúng ta có một vùng chứa chứa img-container
, a
text-container
và a
slider.
Chúng ta sẽ liên kết dữ liệu trong cả 3 vùng chứa bằng chỉ thị *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>
Liên kết sự kiện với slideArray
Sau khi dữ liệu được liên kết, chúng ta sẽ liên kết sự kiện nhấp chuột với mọi nút trượt bằng cách sử dụng click binding
. Chúng ta sẽ tạo một hàm có tên là selected(x)
, trong đó x là chỉ mục của mảng.
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;
}
}
Những điểm cần nhớ:
- Hàm được chọn giảm giá trị của thuộc tính biến đổi 50 lần chỉ mục được truyền khi nhấp vào hàm
selected
. - Logic này dịch vùng chứa văn bản thành 100%, 50%, -50%, -100%, dẫn đến 4 trạng thái khác nhau.
Thêm các phép biến đổi CSS bằng ngStyle và ngClass
Ban đầu, chúng ta đặt tất cả hình ảnh ở độ mờ bằng 0, chúng ta thêm một lớp selected
bằng cách sử dụng ngClass directive
khi chỉ mục đã chọn bằng với chỉ mục hình ảnh. Lớp selected
này thêm độ mờ bằng 1 vào hình ảnh, giúp người dùng nhìn thấy hình ảnh.
<div class="img-container" *ngFor="let i of sliderArray; let select = index;"
[ngClass]="{'selected': select == selectedIndex}">
</div>
Sau đó, chúng ta sẽ dịch vùng chứa văn bản theo giá trị transform
được tính bằng hàm select()
.
<div [ngStyle]="{'transform': 'translateY('+ transform + '%' +')', 'transition': '.8s'}">
</div>
Sau khi thực hiện tất cả các bước này, bạn có thể tìm thấy mã cuối cùng như được cung cấp bên dưới:
<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. Chuyển đổi thành phần thành phần tử góc
Quy trình này bao gồm 5 bước:
- Sử dụng
Shadow DOM
cho phần tử Angular - Tận dụng
entryComponents
- Nhập và sử dụng mô-đun
CreateCustomElement
từ@angular/elements
- Xác định
custom-element
của chúng ta - Phương thức
ngDoBootstrap
đang chạy
Sử dụng DOM bóng cho phần tử góc
Giờ đây, chúng ta đã có trình chiếu hình ảnh đang chạy, chúng ta chỉ cần biến trình chiếu này thành một Angular Element
.
Điều thú vị là chỉ có một thay đổi nhỏ để tạo DOM thành phần, một DOM tối.
Chúng ta cần nhập mô-đun ViewEncapsulation
và phải sử dụng phương thức ShadowDom
từ mô-đun đó.
@Component({
selector: 'app-slider',
templateUrl: './slider.component.html',
styleUrls: ['./slider.component.css'],
encapsulation: ViewEncapsulation.ShadowDom
})
Sử dụng entryComponents
Thành phần nhập là thành phần mà angular tải một cách bắt buộc. Bạn chỉ định một thành phần nhập bằng cách khởi động thành phần đó trong NgModule.
Tại đây, chúng ta sẽ chỉ định SliderComponent
trong mảng entryComponents
bên trong @NgModule
@NgModule({
declarations: [
SliderComponent
],
imports: [
BrowserModule,
HttpClientModule
]
})
Nhập và sử dụng mô-đun createCustomElement
Ở đây, chúng ta cần sử dụng Mô-đun createCustomElement
từ @angular/elements.
Bạn cần sử dụng SliderComponent,
làm tham số cho hàm createCustomElement
. Sau đó, chúng ta cần đăng ký slider
trong DOM.
import { createCustomElement } from '@angular/elements';
export class AppModule {
constructor(private injector: Injector) {
const slider = createCustomElement(SliderComponent, { injector });
}
}
Để đăng ký thanh trượt dưới dạng một phần tử DOM, chúng ta sẽ xác định thanh trượt đó bằng phương thức customElements.define
.
customElements.define('motley-slider', slider);
Cuối cùng, chúng ta phải khởi động phần tử tuỳ chỉnh này bằng phương thức ngDoBootstrap()
. Mã hoàn chỉnh sẽ có dạng như sau:
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() {}
}
Đóng gói Phần tử Angular
Chúng ta cần sửa đổi package.json
bằng các lệnh mới, chúng ta sẽ sửa đổi đối tượng tập lệnh trong tệp package.json
.
Hãy kiểm tra đối tượng tập lệnh đã sửa đổi:
"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"
}
Bây giờ, chúng ta có thể chạy lệnh ng build & ng package
và cuối cùng, chúng ta sẽ chạy ng serve để phân phát thư mục dist/ được tạo bằng lệnh build. Ngoài ra, chúng ta có thể sử dụng gzip
thu được từ lệnh ng package
, trích xuất và xuất bản dưới dạng npm module
.