События мыши Rxjs для достижения желаемой функциональности в угловых 6 - PullRequest
0 голосов
/ 25 июня 2018

Я занимаюсь разработкой углового приложения, в котором UX-дизайнер придумал следующие варианты.

В одном разделе у нас есть 2 подраздела, как на картинке ниже.Normal mode

Когда я наведу курсор на левую часть, эта часть будет анимирована вправо, как показано на рисунке ниже, и появится дополнительный текст

enter image description here

и когда я наведусь на левую часть, она будет анимирована вправо, как показано на рисунке ниже, и появится дополнительный текст:

enter image description here

Я немного приблизился к нему и его CSS-части.

  1. Первое приложение загружается , затем появляется раздел 50-50
  2. , когда япри наведении курсора мыши на левую секцию она должна анимироваться влево (наоборот, при наведении курсора мыши на правую секцию)
  3. Когда я покидаю левую секцию и перемещаю курсор в правую секцию она должна привести влевораздел нормальный и должен анимировать правый раздел (как показано на рис. 3)

Однако, когда я пытаюсь быстро навести курсор на левый и правый раздел, он запускает несколько событий и приводит к нежелательному поведению имоделируется при сtackblitz .

Ниже приведены мои события в компоненте:

import { Component, OnInit, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { fromEvent } from 'rxjs';
import { tap, debounceTime, map, merge, filter, combineLatest, take } from 'rxjs/operators';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {
  @ViewChild('right') right: ElementRef;
  @ViewChild('left') left: ElementRef;
  public showRightText = false;
  public showLeftText = false;
  constructor(private renderer: Renderer2) { }

  ngOnInit() {

    fromEvent(this.right.nativeElement, 'mouseover').pipe(
      debounceTime(1000)
    ).subscribe((e) => {
      console.log("event:Mouseover Right")
      this.renderer.setStyle(this.right.nativeElement, 'width', `150%`);
      this.renderer.setStyle(this.right.nativeElement, 'z-index', `4`);
      setTimeout(() => {
        this.showRightText = true;
      }, 1100);
    });

    fromEvent(this.right.nativeElement, 'mouseleave').subscribe((e) => {
      console.log("event:mouse leave right")
      this.renderer.setStyle(this.right.nativeElement, 'width', `100%`);
      setTimeout(() => {
        this.renderer.removeStyle(this.right.nativeElement, 'z-index');
        this.showRightText = false;
      }, 1100);
    });


    fromEvent(this.left.nativeElement, 'mouseover').pipe(
      debounceTime(1000)
    ).subscribe((e) => {
      console.log("event:Mouseover LEFT")
      this.renderer.setStyle(this.left.nativeElement, 'width', `150%`);
      this.renderer.setStyle(this.left.nativeElement, 'z-index', `4`);
      setTimeout(() => {
        this.showLeftText = true;
      }, 1100);
    });

    fromEvent(this.left.nativeElement, 'mouseleave').subscribe((e) => {
      console.log("event:mouseleave LEFT")
      this.renderer.setStyle(this.left.nativeElement, 'width', `100%`);
      this.showLeftText = false;
      setTimeout(() => {
        this.renderer.removeStyle(this.left.nativeElement, 'z-index');
      }, 1100);
    });
  }
}

Я повторил сценарий в этом stackblitz

1 Ответ

0 голосов
/ 25 июня 2018

Вы используете RxJS как простую замену 'window.addEventListener', но вы МОЖЕТЕ использовать его более мощным способом.Попробуйте использовать что-то вроде этого:

const state$ = merge(
  fromEvent(this.left.nativeElement, "mouseover", () => "LEFT"),
  fromEvent(this.left.nativeElement, "mouseleave", () => "NEUTRAL"),
  fromEvent(this.right.nativeElement, "mouseover", () => "RIGHT"),
  fromEvent(this.right.nativeElement, "mouseleave", () => "NEUTRAL")
);

state$.subscribe((state) => {
  switch(state) {
    case "LEFT":    // yada yada
    case "RIGHT":   // yada yada
    case "NEUTRAL": // yada yada
  }
})

Теперь у вас есть поток состояний.

Затем вы можете сделать его интерактивным в следующей итерации:

const state$ = merge(
  fromEvent(this.left.nativeElement, "mouseover", () => "LEFT"),
  fromEvent(this.left.nativeElement, "mouseleave", () => "NEUTRAL"),
  fromEvent(this.right.nativeElement, "mouseover", () => "RIGHT"),
  fromEvent(this.right.nativeElement, "mouseleave", () => "NEUTRAL")
);

const interativeState$ = switchMap(state$, (state) => {
  return timer(1100).pipe(
    mapTo(true),
    startWith(false),
    map((isShowing) => ({ isShowing, state }))
  );
});

interativeState$.subscribe(({ state, isShowing }) => {
  switch(state) {
    case "LEFT":    // yada yada
    case "RIGHT":   // yada yada
    case "NEUTRAL": // yada yada
  }

  this.showLeftText = isShowing && state === "LEFT";
  this.showRightText = isShowing && state === "RIGHT";
});

switchMap гарантирует, что ваши setTimeouts (как реализовано через timer(1100)) отменяются, когда пользователь взаимодействует с другой стороной ДО ТОГО, как таймер нажмет.

Золотое правило в RxJS: вы должны подписаться только ОДИН РАЗ.В 9/10 случаях это лучший способ структурировать ваше приложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...