Cómo hacer una guía paso a paso de su aplicación (si su proyecto está en Angular)

Hola a todos.

No hace mucho tiempo, terminó el siguiente sprint, y tuve tiempo para hacer que mis usuarios no fueran la característica más necesaria, pero al mismo tiempo interesante: una guía interactiva para trabajar con nuestra aplicación.

Hay muchas soluciones listas para usar en Internet; todas ellas pueden ser adecuadas para esta tarea, pero veremos cómo hacerlo usted mismo.

Arquitectura


La arquitectura de este componente es bastante simple.

Tenemos un elemento importante en el árbol DOM que queremos decirle al usuario algo, por ejemplo, un botón.

Necesitamos dibujar una capa oscura alrededor de este elemento, dirigiéndole la atención.
Debe dibujar una tarjeta junto a este elemento con un mensaje importante.

imagen

Para resolver este problema, @ angular / cdk nos ayudará . En mi último artículo, elogié @ angular / material, que depende del CDK, para mí sigue siendo un ejemplo de componentes de alta calidad creados con todas las características del marco.

Componentes como menús, cuadros de diálogo, barras de herramientas de la biblioteca @ angular / materialhecho usando el componente de CDK - Overlay.

La interfaz simple de este componente le permite crear rápidamente una capa en la parte superior de nuestra aplicación, que se adaptará independientemente a los cambios en el tamaño de la pantalla y el desplazamiento. Como ya entendió, usar este componente para resolver nuestro problema se vuelve muy simple.

Primero, instala las bibliotecas

npm i @angular/cdk @angular/material -S

Después de la instalación, no olvide agregar estilos a style.css

@import '~@angular/cdk/overlay-prebuilt.css';
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';

Ahora cree un nuevo módulo en nuestro proyecto:

ng generate library intro-lib

E inmediatamente genere una plantilla para la directiva:

ng generate directive intro-trigger

Esta directiva actuará como un disparador para nuestra futura guía, escuchará los clics en un elemento y lo resaltará en la página.

@Directive({
  selector: '[libIntroTrigger]'
})
export class IntroTriggerDirective {
  @Input() libIntroTrigger: string;

  constructor(private introLibService: IntroLibService, private elementRef: ElementRef) {}

  @HostListener('click') showGuideMessage(): void {
    this.introLibService.show$.emit([this.libIntroTrigger, this.elementRef]);
  }
}

Aquí pasamos al servicio que también se generó cuando se creó la biblioteca, todo el trabajo principal lo realizará él.

Primero, declarar una nueva propiedad en el servicio

show$ = new EventEmitter<[string, ElementRef]>();

Como ya hemos visto estos valores, la directiva nos enviará, en la matriz, el primer elemento es la descripción, y el segundo es el elemento DOM que describimos (elegí esta solución por simplicidad de ejemplo).

@Injectable({
  providedIn: 'root'
})
export class IntroLibService {
  private overlayRef: OverlayRef;
  show$ = new EventEmitter<[string, ElementRef]>();

  constructor(private readonly overlay: Overlay, private readonly ngZone: NgZone, private readonly injector: Injector) {
    this.show$.subscribe(([description, elementRef]: [string, ElementRef]) => {
      this.attach(elementRef, description);
    });
  }
}

Actualice el diseñador de servicios agregando una suscripción a las actualizaciones de EventEmitter, la función adjuntar recibirá actualizaciones y creará capas.

Para crear la capa necesitamos Overlay, Injector y NgZone.

Las siguientes acciones se pueden dividir en varias etapas:

  • Cerrar la superposición actual (si existe)
  • Crear estrategia de posición
  • Crear OverlayRef
  • Crear portalinyector
  • Adjuntar un componente a una capa

Con los primeros puntos está claro, para esto ya hemos declarado la propiedad en el servicio. PositionStrategy: es responsable de cómo se posicionará nuestra capa en el árbol DOM.

Hay varias estrategias listas para usar:

  1. FlexibleConnectedPositionStrategy
  2. GlobalPositionStrategy

En palabras simples, luego

FlexibleConnectedPositionStrategy: seguirá un elemento específico y, según la configuración, se adherirá a él cuando cambie el tamaño del navegador o el desplazamiento, un claro ejemplo de uso son las listas desplegables, los menús.

GlobalPositionStrategy: como su nombre lo indica, se crea globalmente, no necesita ningún elemento para el trabajo, un ejemplo obvio de uso son las ventanas modales.

Agregue un método para crear una estrategia de ventana flotante alrededor del elemento bajo investigación.

{
 ...
private getPositionStrategy(elementRef: ElementRef): PositionStrategy {
    return this.overlay
      .position()
      .flexibleConnectedTo(elementRef)
      .withViewportMargin(8) //     
      .withGrowAfterOpen(true) //           (, exspansion panel  )
      .withPositions([ //   ,            
        {
          originX: 'start',
          originY: 'bottom',
          overlayX: 'start',
          overlayY: 'top'
        },
        {
          originX: 'start',
          originY: 'top',
          overlayX: 'start',
          overlayY: 'bottom'
        },
        {
          originX: 'end',
          originY: 'bottom',
          overlayX: 'end',
          overlayY: 'top'
        },
        {
          originX: 'end',
          originY: 'top',
          overlayX: 'end',
          overlayY: 'bottom'
        }
      ]);
  }
...
}

Agregue un método para crear OverlayRef

createOverlay(elementRef: ElementRef): OverlayRef {
    const config = new OverlayConfig({
      positionStrategy: this.getPositionStrategy(elementRef),
      scrollStrategy: this.overlay.scrollStrategies.reposition()
    });

    return this.overlay.create(config);
  }

Y agregue un método para vincular nuestro componente a la capa:

  attach(elementRef: ElementRef, description: string): void {
    if (this.overlayRef && this.overlayRef.hasAttached()) {
      this.overlayRef.dispose();
    }

    this.overlayRef = this.createOverlay(elementRef);

    const dataRef = this.ngZone.run(
      () => new DataRef(this.overlay, this.injector, this.overlayRef, elementRef, description)
    ); //   ,      ,    ,  CD    -  

    const injector = new PortalInjector(this.injector, new WeakMap([[DATA_TOKEN, dataRef]]));

    dataRef.overlayRef.attach(new ComponentPortal(IntroLibComponent, null, injector));
  }

Así es como se ve el componente que muestra el mensaje

@Component({
  selector: 'lib-intro-lib',
  template: `
    <mat-card>
      <mat-card-content> {{ data.description }}</mat-card-content>
    </mat-card>
  `,
  styles: ['mat-card {width: 300px; margin: 32px;}']
})
export class IntroLibComponent {
  constructor(@Inject(DATA_TOKEN) public data: DataRef) {}
}

Ya le conté todo lo que resultó en listados, excepto DataRef.

DataRef es una clase simple que agregamos al inyector para componentes, de hecho, para transferir datos para renderizar, por ejemplo, una descripción.

Además, en él decidí dibujar otra capa para oscurecer y resaltar el elemento. En este caso, ya usaremos la estrategia de creación de capa global.

export class DataRef {
  shadowOverlayRef: OverlayRef;

  constructor(
    private overlay: Overlay,
    private injector: Injector,
    public overlayRef: OverlayRef,
    public elementRef: ElementRef,
    public description: string
  ) {
    const config = new OverlayConfig({
      positionStrategy: this.overlay.position().global(),
      scrollStrategy: this.overlay.scrollStrategies.block()
    });

    this.shadowOverlayRef = this.overlay.create(config);

    this.shadowOverlayRef.attach(
      new ComponentPortal(
        ShadowOverlayComponent,
        null,
        new PortalInjector(this.injector, new WeakMap([[DATA_TOKEN, this.elementRef]]))
      )
    );
  }
}


ShadowOverlayComponent: dibuja un componente y en el inyector recibe el mismo token, solo con el elemento alrededor del cual debe enfatizar.

Cómo implementé esto, puede ver en las fuentes en github , no quiero centrarme en esto por separado.

Solo diré que allí dibujo el lienzo a pantalla completa, dibujo una forma alrededor del elemento y relleno el contexto con el método de relleno ('evenodd');

Total


Lo mejor es que @ angular / cdk / overlay nos permite dibujar tantas capas como queramos . Serán adaptables y flexibles. No necesitamos preocuparnos por cambiar el tamaño de la pantalla, o los elementos cambiarán por algunas razones naturales, la superposición lo pensará por nosotros.

Entendimos cómo trabajar con capas, nos dimos cuenta de que la tarea de crear una guía paso a paso no es tan difícil.

Puede modificar la biblioteca agregando la capacidad de cambiar entre elementos, salir del modo de vista y otros casos de esquina.

Gracias por la atención.

Source: https://habr.com/ru/post/undefined/


All Articles