RXJS - испускает только значения больше последнего значения - PullRequest
0 голосов
/ 19 апреля 2019

Я хочу реализовать прослушиватель прокрутки для моего сайта с помощью rxjs.Слушатель в настоящее время испускает каждый номер прокрутки.Возможно ли реализовать прослушиватель с прокруткой, который издает только позицию прокрутки, если число больше, чем раньше БЕЗ ХРАНЕНИЯ СОСТОЯНИЯ СОСТОЯНИЯ .Я хотел бы решить это только с операторами.Текущая реализация выглядит следующим образом:

  public lastScrolledHeight: number = 0;
  ...
  public ngOnInit() {
    this.listenForScroll()
      .subscribe(scrollHeight => {
        this.showAddButton = this.lastScrolledHeight >= scrollHeight; // true or false
        this.lastScrolledHeight = scrollHeight;
      });
  }

  private listenForScroll(): Observable<number> {
    return fromEvent(window, 'scroll').pipe(
      debounceTime(25),
      map((e: any) => e.path[1].scrollY)
    );
  }

подсказки

Одним из подходов уже может быть добавление оператора startsWith(0).Это изменит исходную позицию на 0. Но если scan(), filter() или reduce() помогут, я не могу сказать.

usecase

Я прокручиваю вниз до Y = 300.300 должно быть выброшено.Я прокручиваю до Y = 50. Ничего не должно быть выброшено.Я снова прокручиваю до 150, должно быть выброшено 150.

Ответы [ 4 ]

2 голосов
/ 20 апреля 2019

Полагаю, вы можете использовать для этого попарно:

source$.pipe(
  startWith(-1),
  pairwise(),
  switchMap(([a,b])=>
    b > a
    ? of(b)
    : EMPTY
  )
)

RXJS - Only emit bigger values than the last value

Проверьте этот код на детской площадке

Надеюсь, это поможет

1 голос
/ 22 апреля 2019

Хотя я так благодарен за помощь @Kos и @Daniel за то, что они нашли время помочь мне найти чистое решение, я нашел подход, который является чистым и простым.

fromEvent(document, 'scroll').pipe(
      debounceTime(50),
      // get scrollY
      map((e: any) => e.path[1].scrollY),
      startWith(0),
      distinctUntilChanged(),
      // map the last scroll values into an array
      pairwise(),
      // returns true if delta of prev & curr is greaterOrEqual 0 => scroll up
      map(([prev, curr]: Array<number>) => prev - curr >= 0)
    );
1 голос
/ 21 апреля 2019

Будучи недовольным моим предыдущим подходом, я решил создать пользовательский оператор, охватывающий rxjs.filter и использующий предикат для сравнения текущего значения с предыдущим:

// it will take a predicate to compare values
// by default it will behave as distinctUntilChanged()
const filterChanges = (predicate = ((a,b) => a!==b)) => {
  // store previous value
  let prevValue = void 0;
  return pipe(
    filter((value, index)=>{
      // pass through the first value on stream
      if (index === 0) {
        prevValue = value;
        return value;
      }

      // compare current with prev
      const result = predicate(value, prevValue);
      prevValue = value;
      return result;
    })
  );
};

А потом это так же просто, как передать компаратор:

source$.pipe(
  filterChanges((a, b) => a > b)
)

Выход:

filter changes custom operator

Вот пример игровая площадка .

Надеюсь, это поможет

1 голос
/ 20 апреля 2019

Вы можете использовать оператор scan вместе с distinctUntilChanged:

return fromEvent(window, 'scroll').pipe(
  debounceTime(25),
  map((e: any) => e.path[1].scrollY),
  scan((prev, curr) => Math.max(prev, curr), 0),
  distinctUntilChanged()
)

Что происходит, если наблюдаемое изменено так, чтобы оно содержало максимальное значениетекущей и предыдущей итерации (и имеет значение 0 в качестве начального значения).

После этого distinctUntilChanged() гарантирует, что наблюдаемые не будут повторять повторяющиеся события.

Этогарантирует, что вы будете получать только значения, которые больше, чем предыдущий.

...