إنشاء عنصر شريط تمرير للصور باستخدام Angular

1. مقدمة

بقلم الضيف أيوش أرورا

عناصر Angular هي مكوّنات Angular مجمّعة كعناصر مخصّصة. وهي متوافقة حاليًا مع Chrome وOpera وSafari، وتتوفّر في المتصفّحات الأخرى من خلال polyfills. يمكن أن تستفيد هذه العناصر من بنية Angular الأساسية الكاملة مع واجهة Angular الشائعة واستراتيجية رصد التغيير. بعد التسجيل، يمكن استخدام هذه العناصر داخل المتصفّح.

سيرشدك هذا الدرس العملي خلال عملية إنشاء مكوّن Angular الخاص بك لشريط تمرير الصور، ثم سيساعدك في تحويله إلى عنصر Angular لكي يعمل خارج إطار عمل Angular.

ما ستنشئه

في هذا الدرس العملي، ستنشئ عنصرًا لعرض شرائح الصور باستخدام Angular. Your element wi:

  • تعمل كعنصر HTML في المتصفّح
  • يمكن توصيل أي إطار عمل يتفاعل مع نموذج المستند (DOM).

ما ستتعرّف عليه

  • كيفية إنشاء مكوّن مخصّص لشريط تمرير الصور
  • كيفية تحويل المكوّن المخصّص image-slider إلى عنصر مخصّص
  • كيفية تجميع المكوّن ليعمل داخل المتصفّح

المتطلبات

يركّز هذا الدرس التطبيقي حول الترميز على Angular Elements. يتم تجاهل المفاهيم وكتل الرموز غير ذات الصلة، ويتم توفيرها لك لنسخها ولصقها ببساطة.

2. الإعداد

تنزيل الرمز

انقر على الرابط التالي لتنزيل كل الرموز البرمجية لهذا الدرس العملي:

فكّ ضغط ملف ZIP الذي تم تنزيله. سيؤدي ذلك إلى فك ضغط مجلد جذري (angular-element-codelab-master) يحتوي على

مجلدان (image-slider) و(image-slider-finished) سننفّذ جميع أعمال الترميز في دليل باسم image-slider.

تشغيل المشروع

لتشغيل المشروع، عليك تنفيذ الأمر ( ng-serve ) من الدليل الجذر ( image-slider ).

بعد إعداد التطبيق، سيظهر لك ما يلي:

19ffd082e2f024a5.png

3- Making an Image-Slider custom component ?

كيفية إنشاء شريط تمرير للصور؟

بالنسبة إلى شريط تمرير الصور هذا، اربط الأزرار باستخدام ربط النقر الزاوي. سننشئ مجموعة من العناصر التي تحتوي على صور وعلامات نص بديل وروابط وما إلى ذلك. وسنضع هذه الصور واحدة أسفل الأخرى في حاوية ونترجم الحاوية عند النقر عليها.

سننشئ مكوّنًا منزلقًا للصور، ثم سنحوّله إلى عنصر Angular.

  • حاوية للصور والعناوين
  • مصفوفة تحتوي على البيانات
  • نموذج لربط البيانات

4. تنفيذ مكوّن شريط تمرير الصور

هناك طرق متعددة للبدء في أي مشروع، وفي هذه الحالة، للحفاظ على بساطة مشروعنا قدر الإمكان والتركيز على Angular Elements، قدّمنا لك رمزًا أساسيًا مع CSS.

إنشاء مصفوفة وخدمة بيانات

تذكَّر أنّ 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)
 }
}

استرجاع البيانات من خدمة البيانات

علينا استيراد خدمتنا داخل المكوّن، وبعد ذلك يمكننا الاشتراك في العنصر القابل للمراقبة للحصول على العنصر من data.json

يجب اتّخاذ ثلاث خطوات لإجراء ذلك:

  • تهيئة مصفوفة مكوّنات
  • الاشتراك في Observable الذي تعرضه الدالة 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)=>{
})

تعيين البيانات إلى Component Array

في النهاية، سنعين البيانات إلى مصفوفة المكوّن:

this.data.getData().subscribe((result: Result)=>{  
  this.sliderArray = result.sliderArray;
})

بعد الحصول على البيانات داخل مصفوفة المكوّن، يمكننا ربط النموذج بهذه البيانات.

في slider.component.html,، لدينا نموذج HTML جاهز. خطوتنا التالية هي ربط هذا النموذج بـ sliderArray.

5- ربط البيانات بالنموذج

سنربط البيانات بالنموذج باستخدام توجيه *ngFor، وأخيرًا سنضيف عمليات تحويل في النموذج لتشغيل شريط التمرير.

يتضمّن ذلك ثلاث خطوات:

  • ربط sliderArray بالقالب
  • إضافة ربط الأحداث لأزرار شريط التمرير
  • إضافة تحويلات CSS باستخدام ngStyle وngClass

ربط 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%، ما يؤدي إلى أربع حالات مختلفة.

إضافة عمليات تحويل CSS باستخدام ngStyle وngClass

في البداية، نضبط جميع الصور على مستوى عتامة يساوي صفرًا، ثم نضيف فئة selected باستخدام ngClass directive عندما يصبح الفهرس المحدّد مساويًا لفهرس الصورة. تضيف فئة selected هذه مستوى عتامة يبلغ واحدًا إلى الصورة، ما يجعلها مرئية للمستخدم.

<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

يتألف هذا الإجراء من خمس خطوات:

  • استخدام Shadow DOM لعنصر Angular
  • الاستفادة من 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

علينا تعديل 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.