HammerJS使用Mat-Tabs滑动阻止垂直滚动

时间:2018-06-13 21:43:02

标签: angular angular-material2 hammer.js

所以我的Angular应用程序中有一个组件,其中包含数据类别的选项卡,其中包含选项卡内容的值数组。我想使用HammerJS在标签之间滑动以获得更原生的体验。我还安装了这个虚拟滚动包:https://github.com/rintoj/angular2-virtual-scroll来处理我为每个mat-tab下的列表准备的项目数量。我将首先在此处显示数据和标记:

这里构建dummyData只是为了展示它的结构:

  dummyData: any[] = [];
  selectedTab: number;

  constructor() {
    this.selectedTab = 0;
    for (let i = 0; i < 3; i++) {
      const x = {
        key: i,
        value: []
      }
      for (let j = 0; j < 100; j++) {
        x.value.push(j);
      }
      this.dummyData.push(x);
    }
    console.log(this.dummyData);
  }

以下是循环此数据以显示标签和列表的标记:

  <mat-tab-group dynamicHeight="true" mat-stretch-tabs [selectedIndex]="selectedTab">
    <mat-tab *ngFor="let cat of dummyData" [label]="cat.key">
      <ng-template matTabContent>
        <virtual-scroll [items]="cat.value" (update)="viewPortItems = $event" (swipeleft)="swipe($event)" (swiperight)="swipe($event)" (swipeup)="swipe($event)" (swipedown)="swipe($event)">
          <p *ngFor="let item of viewPortItems; let i = index;">{{ item }}</p>
        </virtual-scroll>
      </ng-template>
    </mat-tab>
  </mat-tab-group>

以下是swipe($event)组件上(swipedirection)输出触发的virtual-scroll方法:

  swipe(event) {
    console.log(event);
    if (this.selectedTab === 0 && event.type === 'swiperight') { return; }
    if ((this.selectedTab + 1) === this.dummyData.length && event.type === 'swipeleft') { return; }
    switch (event.type) {
      case 'swipeleft':
        this.selectedTab += 1;
        break;
      case 'swiperight':
        this.selectedTab -= 1;
        break;
    }
  }

为清楚起见,这是我的Hammer Configuration类和导入:

import * as Hammer from 'hammerjs';
import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';

export class HammerConfig extends HammerGestureConfig {
  overrrides = <any>{
    'swipe': { velocity: 0.4, threshold: 20, direction: Hammer.DIRECTION_ALL },
    'pinch': { enable: false },
    'rotate': { enable: false }
  }
}

还提供了:{ provide: HAMMER_GESTURE_CONFIG, useClass: HammerConfig }

这样做的目的是让用户能够滑动屏幕并在标签之间移动,就像用户在Android或iOS应用程序上一样。此设置正常工作,实际上确实在选项卡之间滑动并接下来加载新数据,并且虚拟滚动数据以确保首先加载一定数量的项目。

我的问题是,当Hammer在touch-action: none组件上设置virtual-scroll时,这会阻止来自移动设备的所有垂直滚动。所以我仍然可以用鼠标滚动,但任何垂直触摸事件都不会做任何事情。我还注意到的一件事是(swipeup)(swipedown)不会在我的组件代码中触发任何事件。我还重新调整了swipeup和swipeown输出,以确保它们不会阻碍滚动,但在屏幕上垂直向上或向下拖动时仍然没有。

我也可以确认这与使用virtual-scroll软件包没有问题,因为我尝试使用普通的div而不是试图延迟加载项目,但只是一次加载它们。仍然会遇到阻止任何垂直滚动方向的相同问题。由于我将使用virtual-scroll因为标签的手势更重要,所以我想在标记中显示我的示例。

任何人都能找到一种方法来保持原生虚拟滚动,同时启用水平滑动手势?

我非常感谢这里的所有帮助,提前谢谢!

1 个答案:

答案 0 :(得分:0)

我想出了一种在保持垂直触摸动作的同时完成这项工作的方法。我现在使用的锤子配置看起来像这样:

export class HammerConfig extends HammerGestureConfig {
  overrrides = <any>{
    'swipe': { velocity: 0.4, threshold: 20, direction: Hammer.DIRECTION_ALL },
    'pinch': { enable: false },
    'rotate': { enable: false },
    'pan': { velocity: 0.4, threshold: 20, enable: true, direction: Hammer.DIRECTION_ALL }
  }
}

pan设置为启用。

然后我在标记上使用(panend)输出:(panend)="swipe($event)",而不是(swipedirection)输出,这是我的编辑滑动方法:

  swipe(event) {
    console.log(event);
    event.preventDefault();
    if (this.selectedTab === 0 && event.additionalEvent === 'panright') { return; }
    if ((this.selectedTab + 1) === this.menu$.length && event.additionalEvent === 'panleft') { return; }
    switch (event.additionalEvent) {
      case 'panleft':
        this.selectedTab += 1;
        break;
      case 'panright':
        this.selectedTab -= 1;
        break;
    }
  }

从这里开始,这仍会阻止任何垂直滚动,但是重新启用垂直滚动的一件事是在我的touch-action: pan-y元素上设置virtual-scroll样式:

virtual-scroll {
    height: calc(100vh - 106px);
    padding: 0px 0px;
    will-change: transform;
    touch-action: pan-y !important;
}

根据我的理解,这告诉系统在y方向滚动时允许原生触摸操作,但x方向将触发panend事件,我可以从那里管理我的选项卡索引。我希望这可以帮助其他任何试图在保持垂直滚动行为的同时使用左右手势的人。