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

时间:2019-04-19 08:34:33

标签: angular functional-programming rxjs observable

我想使用rxjs为我的网站实现滚动侦听器。侦听器当前发出每个scrollY号。如果数字大于之前的不存储状态全属性,是否可以实现只显示滚动位置的滚动侦听器。我只想和运营商解决这个问题。当前的实现如下所示:

  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。

4 个答案:

答案 0 :(得分:2)

我想,您可以为此成对使用

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 :(得分: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()
)

发生的事情是将可观察对象修改为包含当前迭代和上一个迭代的最大值(并且其初始值为0)。

此后,distinctUntilChanged()确保可观察对象不会发出重复事件。

这可以确保您只会收到比上一个更大的值。

答案 2 :(得分: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

希望这会有所帮助

答案 3 :(得分: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)
    );