RXJS - 仅发出比上一个值更大的值

问题描述 投票:0回答:4

我想用rxjs为我的网站实现一个滚动监听器。监听器当前发出每个滚动号码。如果数字高于之前没有存储STATEFULL属性,是否可以实现仅发出滚动位置的滚动侦听器。我想只与运营商解决这个问题。目前的实现如下:

  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()会有所帮助,我不能说。

用例

我向下滚动到Y = 300。应该发出300。我向上滚动到Y = 50.什么都不应该发出。我再次向下滚动到150,应该发出150。

angular functional-programming rxjs observable
4个回答
1
投票

由于对我以前的方法不满意,我决定创建一个包含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

继承人playground example

希望这可以帮助


2
投票

我想,你可以使用pairwise:

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

RXJS - Only emit bigger values than the last value

检查此代码in a playground

希望这可以帮助


1
投票

你可以使用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()
)

会发生什么是修改observable以包含当前和上一次迭代的最大值(并且值为0作为其初始值)。

之后,distinctUntilChanged()确保观察者不会发出重复事件。

这可确保您只接收大于前一个值的值。


1
投票

虽然我非常感谢@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)
    );
© www.soinside.com 2019 - 2024. All rights reserved.