Compila un elemento de deslizador de imágenes con Angular

Escrito por el autor invitado Aayush Arora

Los elementos de Angular son componentes de Angular empaquetados como elementos personalizados. Son compatibles con Chrome, Opera y Safari, y se pueden usar en otros navegadores con polyfills. Pueden utilizar toda la infraestructura de Angular con la interfaz regular de Angular y la estrategia de detección de cambios. Una vez que se registran, estos elementos se pueden usar en el navegador.

Este codelab te servirá como guía para crear tu propio componente de deslizador de imágenes de Angular y, luego, te ayudará a transformarlo en un elemento de Angular a fin de que funcione fuera del framework de Angular.

Qué compilarás

En este codelab, compilarás un elemento de deslizador de imágenes con Angular Tu elemento podrá:

  • funcionar como un elemento HTML en el navegador
  • conectarse a cualquier framework que se comunique con el DOM

Qué aprenderás

  • Cómo crear un componente personalizado de deslizador de imágenes
  • Cómo transformar el componente personalizado de deslizador de imágenes en un elemento personalizado
  • Cómo empaquetar el componente para que funcione dentro del navegador

Requisitos

Este codelab se enfoca en los elementos de Angular Los conceptos y los bloques de código que no son relevantes no se explican, pero se proporcionan para que los copies y pegues.

Descarga el código

Haz clic en el siguiente vínculo para descargar el código de este codelab:

Descargar código fuente

Descomprime el archivo ZIP descargado. Se descomprimirá una carpeta raíz (angular-element-codelab-master) que contiene

dos carpetas: (image-slider) y (image-slider-finished). Haremos toda nuestra edición de código en el directorio llamado image-slider.

Ejecuta el proyecto

Para ejecutar el proyecto, debes utilizar el comando ( ng-serve ) desde el directorio raíz ( control de imagen ).

Una vez que se inicialice la app, verás lo siguiente:

19ffd082e2f024a5.png

¿Cómo crear un deslizador de imágenes?

Para este deslizador de imágenes, vincula los botones con el vínculo de clics de Angular. Crearemos un array de objetos con imágenes, etiquetas ALT, vínculos, etc. Colocaremos estas imágenes una debajo de la otra en un contenedor y traduciremos el contenedor cuando se haga clic en él.

Crearemos también un componente de deslizador de imágenes y lo transformaremos en un elemento de Angular.

  • Contenedor para imágenes y títulos
  • Un array que contiene los datos
  • La plantilla para vincular los datos

Hay varias maneras de comenzar con cualquier proyecto, en este caso, para que tu proyecto sea lo más simple posible y concentrarte en los elementos de Angular, hemos proporcionado el código básico junto con los recursos CSS.

Crea un array y un servicio de datos

Recuerda que el sliderArray contiene lo siguiente:

  • Una clave img para la URL de la imagen del deslizador
  • Una etiqueta ALT para proporcionar alternativas para la imagen
  • Un texto para proporcionar la descripción de la imagen

El archivo data.json que ya está en el directorio src/assets debe verse de la siguiente manera:

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'}
];

Necesitamos obtener estos datos en nuestro componente mediante un servicio. En el archivo data.service.ts, escribiremos un método getData() con el módulo httpClient de @angular/common/http, que recuperará los datos del array que creamos anteriormente.


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)
 }
}

Recupera los datos del servicio de datos

Necesitamos importar nuestro servicio dentro del componente y, luego, suscribirnos al observable para obtener el objeto de data.json

Debemos realizar los tres pasos siguientes:

  • Inicializar un array de componentes
  • Suscribirse al observable que devuelve la función getData()
  • Crear un resultado de interfaz para la comprobación de tipos de datos después de suscribirse al observable
  • Asignar los datos al array de componentes

Inicializa el array de componentes

Declararemos e inicializaremos el array de componentes dentro de slider.component.ts, que es un vector de elementos:

Para declararlo:

sliderArray: object[];

Para inicializarlo:

constructor(private data: DataService) {
 this.sliderArray = [];
}

A continuación, debemos importar e inicializar nuestro servicio dentro del constructor.

constructor(private data: DataService) {}

Ya estamos listos para usar nuestro servicio y llamar a nuestros métodos de servicios.

Obtén datos del servicio de datos

Para recibir los datos del servicio, llamaremos al método getData() y nos suscribiremos al observable que devuelve. También crearemos una interfaz Result, para comprobar que obtenemos los tipos de datos correctos.

Haremos esto dentro del método ngOnInit:

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

Asigna datos al array de componentes

Al final, asignaremos los datos al array de componentes:

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

Una vez que tenemos los datos dentro de nuestro array de componentes, podemos vincular nuestra plantilla con esos datos.

En slider.component.html,, ya tenemos una plantilla HTML. El próximo paso es vincular esta plantilla con el sliderArray.

Vincularemos los datos con la plantilla mediante la directiva *ngFor y, por último, agregaremos transformaciones en la plantilla para que el deslizador funcione.

El proceso consiste en tres pasos:

  • Vincular sliderArray a la plantilla
  • Agregar una vinculación de eventos para los botones del deslizador
  • Agregar transformaciones CSS mediante ngStyle y ngClass

Vincula slideArray al componente

Tenemos un contenedor que tiene un img-container, text-container y slider..

Vincularemos los datos de los tres contenedores usando la directiva *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>

Vincula eventos a slideArray

Una vez que se hayan vinculado los datos, enlazaremos el evento de clic con cada botón de deslizamiento a través de click binding de Angular. Crearemos una función llamada selected(x), donde "x" es el índice del array.

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;
  }
}

Cuestiones que debes tener en cuenta aquí:

  • La función downselected reduce el valor de la propiedad transformación cincuenta veces el valor del índice que se pasó a la función al hacer clic en selected.
  • Esta lógica traduce el contenedor de texto a 100%, 50%, -50%, -100%, lo que da como resultado cuatro estados diferentes.

Agrega transformaciones de CSS con ngStyle y ngClass

Inicialmente, establecemos todas las imágenes con una opacidad cero. Luego, agregamos una clase selected usando una ngClass directive cuando el índice seleccionado es igual al índice de imagen. Esta clase selected agrega una opacidad de "uno" a la imagen y la hace visible para el usuario.

<div class="img-container"  *ngFor="let i of sliderArray; let select = index;"
      [ngClass]="{'selected': select == selectedIndex}">
</div>

Después de esto, traduciremos el contenedor de texto según el valor transform que se calculó mediante la función select().

<div [ngStyle]="{'transform': 'translateY('+ transform + '%' +')', 'transition': '.8s'}">
</div>

Después de realizar estos pasos, el código final se verá de la siguiente forma:

<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>

El procedimiento consta de cinco pasos:

  • Utilizar Shadow DOM para el elemento de Angular
  • Hacer uso de entryComponents
  • Importar y usar el módulo CreateCustomElement de @angular/elements
  • Definir nuestro custom-element
  • Ejecutar el método ngDoBootstrap

Utiliza Shadow DOM para los elementos de Angular

Ahora que tenemos el deslizador de imágenes funcionando, solo necesitamos que sea un Angular Element.

La parte divertida es que solo hay que hacer un pequeño cambio para que el componente DOM sea un Shadow DOM.

Necesitamos importar el módulo ViewEncapsulation y utilizar el método ShadowDom a partir de allí.

@Component({
 selector: 'app-slider',
 templateUrl: './slider.component.html',
 styleUrls: ['./slider.component.css'],
 encapsulation: ViewEncapsulation.ShadowDom
})

Utiliza entryComponents

El componente de entrada es un componente que Angular carga de manera imperativa. Debes especificar un componente de entrada, declarándolo dentro de un NgModule para el arranque inicial.

Aquí, especificaremos SliderComponent en el array entryComponents dentro de @NgModule.

@NgModule({
 declarations: [
   SliderComponent
 ],
 imports: [
   BrowserModule,
   HttpClientModule
 ]
})

Importa y utiliza el módulo createCustomElement

Aquí, debemos usar el módulo createCustomElement de @angular/elements.. Debes usar SliderComponent, como parámetro para la función createCustomElement. Luego, necesitamos registrar el slider en el DOM.

import { createCustomElement } from '@angular/elements';

export class AppModule {
 constructor(private injector: Injector) {
   const slider = createCustomElement(SliderComponent, { injector });
    }
}

Para registrar el deslizador como un elemento del DOM, lo definiremos con el método customElements.define.

customElements.define('motley-slider', slider);

Por último, debemos inicializar este elemento personalizado con el método ngDoBootstrap(). El código completo se verá de la siguiente forma:

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() {}

}

Empaqueta el elemento de Angular

Debemos modificar package.json con nuestros nuevos comandos. Para ello, modificaremos el objeto de la secuencia de comandos dentro del archivo package.json.

Veamos nuestro objeto de secuencia de comandos modificado:

"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"
}

Ahora, podemos ejecutar el comando ng build & ng package y, finalmente, ejecutaremos ng serve para entregar la carpeta dist/ carpeta que se generó con el comando de compilación. Además, podemos usar el gzip que obtuvimos del comando ng package, extraerlo y publicarlo como un npm module.