Angular 使用原生事件和 rxjs 滑动页面

Angular swipe pages with native events and rxjs

我想使用本机事件和 rxjs 在 angular 中的页面之间滑动。我找到 this 并更改了我的代码以使用 rxjs:

ngAfterViewInit(): void {
  fromEvent<TouchEvent>(document, 'touchstart')
    .pipe(
      switchMap(() =>
        fromEvent<TouchEvent>(document, 'touchmove').pipe(
          takeUntil(fromEvent(document, 'touchend')),
          pairwise()
        )
      )
    )
    .subscribe(([touchstartEvent, touchendEvent]) => {
      const xDiff =
        touchstartEvent.touches[0].clientX - touchendEvent.touches[0].clientX;
      console.log(xDiff);

      if (Math.abs(xDiff) < 0.3 * document.body.clientWidth) {
        return;
      }

      if (xDiff > 0) {
        console.log('right swipe');
      } else {
        console.log('left swipe');
      }
    });
}

然而,我在订阅中的函数被调用了多次,这意味着我的滑动从未被执行,因为我的 treshhold 0.3 * document.body.clientWidth 从未被满足。为了调试,我添加了以下代码:

fromEvent(document, 'touchend').subscribe((e) => {
  console.log('test2');
});

然后我的控制台输出是这样的,显示 takeUntil 没有按预期工作:

test -24.941162109375
test -8
test -9.41180419921875
test -8.4705810546875
test -9.88232421875
test2

我在这里错过了什么?

此处 pairwise() 运算符的用法是错误的。根据您的预期排放量 [touchstartEvent, touchendEvent]pairwise() 并没有按照您认为的那样进行。发出的实际值是 [touchmove[0], touchmove[1]].

我建议如下

  1. 使用 zipWith 运算符合并 touchstarttouchend 并忽略 touchmove 如果它的值不是必需的。

  2. 在订阅回调中使用 return 来停止进一步执行对我来说并不优雅。您可以改为翻转 if 语句的条件。

ngAfterViewInit(): void {
  fromEvent<TouchEvent>(document, 'touchstart')
    .pipe(zipWith(fromEvent<TouchEvent>(document, 'touchend')))
    .subscribe({
      next: ([touchstartEvent, touchendEvent]) => {
        const xDiff = 
          touchstartEvent.touches[0].clientX - touchendEvent.touches[0].clientX;
        console.log(xDiff);
        if (Math.abs(xDiff) > 0.3 * document.body.clientWidth) {
          if (xDiff > 0) {
            console.log('right swipe');
          } else {
            console.log('left swipe');
          }
        }
      }
    });
}

工作示例(触摸事件替换为鼠标事件):Stackblitz

不幸的是,Michaels 的回答只适用于鼠标事件,因为 endtouch 事件不包含 clientX 信息。

因此我调整了他的回答:

ngAfterViewInit(): void {
  fromEvent<TouchEvent>(document, 'touchstart')
    .pipe(
      zipWith(
        fromEvent<TouchEvent>(document, 'touchend').pipe(
          withLatestFrom(fromEvent<TouchEvent>(document, 'touchmove'))
        )
      )
    )
    .subscribe(([touchstart, [_, touchmove]]) => {
      const xDiff =
        touchstart.touches[0].clientX - touchmove.touches[0].clientX;
      console.log(xDiff);
      if (Math.abs(xDiff) > 0.3 * document.body.clientWidth &&
          touchstart.timeStamp <= touchmove.timeStamp) {
        if (xDiff > 0) {
          console.log('right swipe');
        } else {
          console.log('left swipe');
        }
      }
    });
}