Angular2:使用HammerJS在md-tab-group中进行滑动操作

3
我已经在我的 Angular2 网页应用中实现了 HammerJS,并且我也测试了 example 代码。这个代码使用了一个对象数组,似乎运行得非常顺畅。然而,我一直在尝试为 @angular2-material/tabs 实现相同的系统。因此,我有一个包含多个 <md-tab><md-tab-group>,它们应该从一个选项卡滑动到另一个选项卡。问题是,我甚至无法触发滑动功能。 HTML文件:
<md-tab-group md-stretch-tabs [(selectedIndex)]="selectedIndex" (selectedIndexChange)="selectChange()">
      <div class="swipe-box" (swipeleft)="swipe(idx, $event.type)" (swiperight)="swipe(idx, $event.type)">
        <md-tab>
           (...) //Content Tab 1
        </md-tab>
        <md-tab>
           (...) //Content Tab 2
        </md-tab>
      </div>
</md-tab-group>

在示例中可以看到,*ngFor被用于swipe-box-
,形式为*ngFor="let avatar of avatars; let idx=index"。但由于我从<md-tab-group>中获取我的索引,似乎并不必要,即使包含它,我的事件也不会触发,但是我的<md-tab>内容将变得隐藏。因此我将其省略了。我在函数中保留了idx参数,因为swipe方法需要一个数字(第二个参数是可选的)。文档

对于TypeScript文件,我实现了以下代码(某些代码可能无法运行,因为swipe方法不会被调用)。

TS文件

export class HomeComponent {

  selectedIndex: number = 1;

  selectChange(): void{
    console.log("event triggered INDEX: " + this.selectedIndex);
  }

  SWIPE_ACTION = { LEFT: 'swipeleft', RIGHT: 'swiperight' };

  // Action triggered when user swipes
  swipe(selectedIndex: number, action = this.SWIPE_ACTION.RIGHT) {
    console.log("swiped"); //DOES NOT GET TRIGGERD
    // Out of range
    if (selectedIndex < 0 || selectedIndex > 1 ) return;

    let nextIndex = 0;
    // Swipe right, next tab
    if (action === this.SWIPE_ACTION.RIGHT) {
      const isLast = selectedIndex === 1;
      nextIndex = isLast ? 0 : selectedIndex + 1;
      console.log("swipe right");
    }

    // Swipe left, previous tab
    if (action === this.SWIPE_ACTION.LEFT) {
      const isFirst = selectedIndex === 0;
      nextIndex = isFirst ? 1 : selectedIndex - 1;
      console.log("swipe left");
    }
  }
}

HammerJS 的实时演示 ,是的,我已经在 index.html 中实现了所需的脚本。

<!-- Hammer JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
3个回答

9
我写了一个小指令来实现与您的代码相同的效果:
import { Directive, HostListener, EventEmitter, Input, Output } from '@angular/core';

@Directive({
  selector: '[swipeTab]'
})
export class SwipeTabDirective {

  @HostListener('swipeleft', ['$event'])
  onSwipeleft(event) {
    if(this.selectedIndex + 1 <= this.tabs - 1) {
      this.selectedIndex += 1;
      this.selectedIndexChange.emit(this.selectedIndex);
    }
  }

  @HostListener('swiperight', ['$event'])
  onSwiperight(event) {
    if(this.selectedIndex - 1 >= 0) {
      this.selectedIndex -= 1;
      this.selectedIndexChange.emit(this.selectedIndex);
    }
  }

  @Input() tabs: number;
  @Input()  selectedIndex: number;
  @Output() selectedIndexChange = new EventEmitter<number>();

}

模板应该长这样:

<md-tab-group md-stretch-tabs [(selectedIndex)]="selectedIndex" [(tabs)]="tabs" swipeTab>
       <md-tab>
          (...) //Content Tab 2
       </md-tab>
       <md-tab>
          (...) //Content Tab 2
       </md-tab>
       <md-tab>
          (...) //Content Tab 3
       </md-tab>           
</md-tab-group>

在组件中,您需要声明以下变量:

  selectedIndex: number = 0;
  tabs: number = 3;

玩得开心。


1
不,你仍然需要HammerJS,因为swipeleft和swiperight事件来自于HammerJS。 - Max Payne
1
嘿@MaxPayne,HTML说无法绑定到“tabs”,因为它不是“div”的已知属性。尽管我已在组件文件中声明了“tabs”。 - Humble Dolt
  1. 它对我起作用了 :)!
  2. 确保导入hammerjs,以便指令可以正常工作:https://medium.com/the-dev-newbie/integrating-hammerjs-with-angular-7fab8186510c
  3. 记得在正确的模块中导入SwipeTabDirective!
- Jacob

6

问题似乎出现在滑动事件使用在了错误的<div>上。该事件需要在父级<div>中触发。以下是有效的代码:

HTML文件

<div class="md-content" flex md-scroll-y (swipeleft)="swipe(idx, $event.type)" (swiperight)="swipe(idx, $event.type)">
   <md-tab-group md-stretch-tabs [(selectedIndex)]="selectedIndex" (selectedIndexChange)="selectChange()">
           <md-tab>
              (...) //Content Tab 1
           </md-tab>
           <md-tab>
              (...) //Content Tab 2
           </md-tab>
   </md-tab-group>
</div

TS-File:

export class HomeComponent {

  selectedIndex: number = 1;

  selectChange(): void{
    console.log("Selected INDEX: " + this.selectedIndex);
  }

  SWIPE_ACTION = { LEFT: 'swipeleft', RIGHT: 'swiperight' };

  // Action triggered when user swipes
  swipe(selectedIndex: number, action = this.SWIPE_ACTION.RIGHT) {
    // Out of range
    if (this.selectedIndex < 0 || this.selectedIndex > 1 ) return;

    // Swipe left, next tab
    if (action === this.SWIPE_ACTION.LEFT) {
      const isLast = this.selectedIndex === 1;
      this.selectedIndex = isLast ? 0 : this.selectedIndex + 1;
      console.log("Swipe right - INDEX: " + this.selectedIndex);
    }

    // Swipe right, previous tab
    if (action === this.SWIPE_ACTION.RIGHT) {
      const isFirst = this.selectedIndex === 0;
      this.selectedIndex = isFirst ? 1 : this.selectedIndex - 1;
      console.log("Swipe left - INDEX: " + this.selectedIndex);
    }
  }
}

3
您需要在每个选项卡上进行滑动检测,而不是容器。
  <div class="swipe-box">
    <md-tab (swipeleft)="swipe(1, $event.type)" 
            (swiperight)="swipe(1, $event.type)">
       (...) //Content Tab 1
    </md-tab>
    <md-tab (swipeleft)="swipe(2, $event.type)" 
            (swiperight)="swipe(2, $event.type)">
       (...) //Content Tab 2
    </md-tab>
  </div>

算了,示例中<div>也有它,所以那不应该是问题。 - Wouter Vanherck
1
是的,但DIV使用*ngFor进行复制,因此滑动处理程序最终会在每个头像div上。检查运行中的代码。您上面的解决方案也有效,因为选项卡组保留了所选索引。有趣的东西。很高兴您解决了它 :) - Dan
1
谢谢您详细阐述这个问题。就像我之前所说的,这确实有可能是一个问题,而您的解释完美地解释了为什么会出现这种情况,非常感谢! - Wouter Vanherck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接