Излучать из наблюдаемой, только если другая наблюдаемая не излучала в течение последних двух секунд - PullRequest
1 голос
/ 24 марта 2020

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

Проблема: у меня есть 'go to top' кнопка, функция которой состоит в том, чтобы прокрутить пользователя вверх страницы. Он не должен быть видимым, когда пользователь фактически находится наверху.

Его видимость в настоящее время обрабатывается с помощью анимированного атрибута непрозрачности, но с ним можно взаимодействовать благодаря отображению: ни один из них не применяется. Поэтому я должен найти способ отображения: ни один не применяется при непрозрачности 0.

Первая реализация, в Angular, должна сделать что-то вроде этого:

    @HostListener('window:scroll', ['$event'])
    scrolled(_event: Event) {
        if (window.pageYOffset === 0) {
            setTimeout(() => (this.noClick = true), 1000);
        } else {
            this.noClick = false;
        }

        this.show = window.pageYOffset > 0;
    }

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

Однако существует условие гонки, где пользователь может прокрутить вниз после прокрутки до 0, и задержка все еще может установить noClick в значение true.

Я хотел бы рассмотреть Observable для решения этой проблемы.

Если у меня есть два предмета :

displayNone = new Subject<boolean>();   // only contains true values
displaySome = new Subject<boolean>();   // only contains false values

и некоторый код события:

    @HostListener('window:scroll', ['$event'])
    scrolled(_event: Event) {
        if (window.pageYOffset === 0) {
            this.displayNone.next(true);
        } else {
            this.displaySome.next(false);
        }

        this.show = window.pageYOffset > 0;
    }

Мне нужно создать наблюдаемую для функциональности displayNone, где, если displayNone задерживается 1000 мс (время анимации) и в в это время displaySome излучает, оно должно игнорировать displayNone.

Самое близкое, на что я могу прийти сейчас, это что-то вроде этого:

race(this.displaySome, this.displayNone.pipe(delay(1000)))

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

1 Ответ

0 голосов
/ 24 марта 2020

Вам не нужны две Observables, чтобы показать / скрыть кнопку с анимацией. Лучшее решение вашей проблемы отличается от ответа на ваш вопрос. Я пытаюсь ответить на оба вопроса.

Только испускать, если другой Наблюдаемый не испускал в течение последних X миллисекунд

const X = 1000;
const obs$ = source$.pipe(
  // emit values on a new inner Observable when the otherObservable$ emits
  window(otherObservable$),
  // skip all values on this inner Observable until a given time has passed
  // (but not for the first inner Observable created before otherObservable$ emits)
  mergeMap((w, i) => i == 0 ? w : w.pipe(skipUntil(timer(X))))
);

Показать / скрыть кнопку в зависимости от событий прокрутки

  1. Создание Observable из событий прокрутки и сопоставление с логическим значением, указывающим, показывать или скрывать кнопку.
hasScrolledDown$: Observable<boolean>;

ngOnInit() {
  this.hasScrolledDown$ = fromEvent(window, 'scroll').pipe(
    throttleTime(20),
    map(() => window.pageYOffset > 50)
  )
}
Используйте ngIf, чтобы показать / скрыть кнопку в зависимости от значения из наблюдаемого.
<button *ngIf="hasScrolledDown$ | async">
(Необязательно) Добавление анимации для изменений состояния enter и leave.
<button *ngIf="hasScrolledDown$ | async" [@fadeAnimation]>
export const fadeOutAnimation = animation([
    style({ opacity: 1 }),
    animate('200ms', style({ opacity: 0 }))
])

export const fadeInAnimation = animation([
    style({ opacity: 0 }),
    animate('200ms', style({ opacity: 1 }))
])

@Component({
  selector: 'button-overview-example',
  templateUrl: 'button-overview-example.html',
  styleUrls: ['button-overview-example.css'],
  animations: [
    trigger('fadeAnimation', [
      transition(':enter', [useAnimation(fadeInAnimation)]),
      transition(':leave', [useAnimation(fadeOutAnimation)])
    ])
  ],
})

Демо

...