在Angular 2中实现滑动导航的最佳方法是什么?

29

我是Angular 2的新手,正在寻找一种适用于移动用户的好的标签触摸滑动导航方式,并希望能够实现从一个标签视图向下一个标签视图的滑动转换。

到目前为止,我发现了一个名为angular2-useful-swiper的软件包,但我不太愿意使用它,因为即使它们不在视图中,我也会提前初始化我的组件。

有没有人知道一种在Angular 2中实现标签滑动导航的好方法?任何反馈都将不胜感激. : )

5个回答

96

这里提供一个比添加 HammerJS 更简单的解决方案来进行滑动检测:

在 app.component.html 中:

<div (touchstart)="swipe($event, 'start')" (touchend)="swipe($event, 'end')">
  App content here
</div>

在 app.component.ts 中:

private swipeCoord?: [number, number];
private swipeTime?: number;

swipe(e: TouchEvent, when: string): void {
  const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
  const time = new Date().getTime();

  if (when === 'start') {
    this.swipeCoord = coord;
    this.swipeTime = time;
  } else if (when === 'end') {
    const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
    const duration = time - this.swipeTime;

    if (duration < 1000 //
      && Math.abs(direction[0]) > 30 // Long enough
      && Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
        const swipe = direction[0] < 0 ? 'next' : 'previous';
        // Do whatever you want with swipe
    }
  }
}
注意:我尝试了 HammerJS 的解决方案,但配置它以忽略鼠标手势是不可能的,因为你无法直接访问 Hammer 对象。因此,选择一些文本会强制导航到下一页...

注意:我尝试了 HammerJS 的解决方案,但由于无法直接访问 Hammer 对象,因此无法配置它以忽略鼠标手势。因此,选择文本会强制导航到下一页...


我在hammer.js的github上的一个bug问题中发布了你写得很好的解决方案,希望他们在那之后能够对我们使用它时遇到的问题做出反应... - sebius
这是非常轻量级和棒极了的解决方案,唯一的小漏洞是如果您在相邻位置双击(如弹奏键盘),它会将其检测为滑动。 - ishandutta2007
2
这个小指令怎么样?https://github.com/aGoncharuks/angular-swipe-directive - Naveed Ahmed
@pikiou 这太棒了,谢谢你。 - Jay
@Naveed Ahmed,那个指令很酷,但只适用于Angular 14及以下版本。 - Jay

12

我根据 @Elvis Metodiev 和 @pikiou 的回答创建了一个指令:

swipe.directive.ts

import { Directive, EventEmitter, HostListener, Output } from '@angular/core';

@Directive({ selector: '[swipe]' })
export class SwipeDirective {

    @Output() next = new EventEmitter<void>();
    @Output() previous = new EventEmitter<void>();

    swipeCoord = [0, 0];
    swipeTime = new Date().getTime();

    constructor() { }

    @HostListener('touchstart', ['$event']) onSwipeStart($event) {
        this.onSwipe($event, 'start');
    }

    @HostListener('touchend', ['$event']) onSwipeEnd($event) {
        this.onSwipe($event, 'end');
    }

    onSwipe(e: TouchEvent, when: string) {
        this.swipe(e, when);
    }

    swipe(e: TouchEvent, when: string): void {

        const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
        const time = new Date().getTime();

        if (when === 'start') {
            this.swipeCoord = coord;
            this.swipeTime = time;
        } else if (when === 'end') {
            const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]];
            const duration = time - this.swipeTime;

            if (duration < 1000 //
                && Math.abs(direction[0]) > 30 // Long enough
                && Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
                const swipeDir = direction[0] < 0 ? 'next' : 'previous';
                if (swipeDir === 'next') {
                    this.next.emit();
                } else {
                    this.previous.emit();
                }
            }
        }
    }
}

tour.component.component.ts

<div
  ...
  swipe
  (next)="onRotateNext()"
  (previous)="onRotatePrevious()"
>
...
</div>

11

您可以使用 HammerJS 实现触摸操作,您可以参考此示例

包含hammer.js文件

<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
或者
npm install hammerjs --save

要在浏览器中使用hammerjs支持触摸,需要包含以下内容

 <script src="http://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script>
<script>

在 app.module.ts 中导入

import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';

export class MyHammerConfig extends HammerGestureConfig  {
  overrides = <any>{
    'swipe': {velocity: 0.4, threshold: 20} // override default settings
  }
}

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [{ 
    provide: HAMMER_GESTURE_CONFIG, 
    useClass: MyHammerConfig 
  }] // use our custom hammerjs config
})

plunker示例链接

要实现选项卡,可以从angular2-material开始学习,参考此链接


1
Hammer.js已不再维护,请更新您的答案,以便其他人能立即看到。 :) - MikhailRatner

5

首先安装hammerjs和touch-action polyfill插件:

$ npm install hammerjs hammer-timejs

然后将这些导入添加到“app.module.ts”中,以便它们将被使用/捆绑在一起:
import 'hammerjs';
import 'hammer-timejs';

现在您可以处理以下操作的事件:

  • 旋转(Rotate)
  • 捏合(Pinch)
  • 按下(Press)
  • 平移(Pan)
  • 轻击(Tap)
  • 滑动(Swipe)

例如,您可以说:

<li *ngFor="let employee of employeesList;" (swiperight)="myswiperight(employee)" (swipeleft)="myswipeleft(employee)">

或者:

<div (panstart)="onPanStart($event)" (panmove)="onPan($event)">

参考资料:https://saschwarz.github.io/angular2-gestures-slides/#/


0

我成功地想出了一种编写一次,随处可用的函数类型,我将其放在一个名为“gestures”的目录中,然后创建了一个名为“swipe.ts”的文件并将其放在其中。

let swipeCoord = [0, 0];
let swipeTime = new Date().getTime();

export function swipe(e: TouchEvent, when: string): void {

    const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY];
    const time = new Date().getTime();

    if (when === 'start') {
        swipeCoord = coord;
        swipeTime = time;
    } else if (when === 'end') {
        const direction = [coord[0] - swipeCoord[0], coord[1] - swipeCoord[1]];
        const duration = time - swipeTime;

        if (duration < 1000 //
            && Math.abs(direction[0]) > 30 // Long enough
            && Math.abs(direction[0]) > Math.abs(direction[1] * 3)) { // Horizontal enough
            const swipeDir = direction[0] < 0 ? 'next' : 'previous';
            if (swipeDir === 'next') {
                alert('swipe next');
            } else {
                alert('swipe prev');
            }
        }
    }
}

然后将其导入到所需的组件中,就像这样:

import {swipe} from '../../gestures/swipe';

创建一个名为“”(空白)的函数:
onSwipe(e: TouchEvent, when: string) {
        swipe(e, when);
    }

在所需组件的HTML中,使用以下代码:
    <div (touchstart)="onSwipe($event, 'start')"
         (touchend)="onSwipe($event, 'end')">

       <!-- whatever content you have goes here -->

    </div>

PS - 感谢 @pikiou。我只是想出了一个更高层次的抽象,对我来说更有意义。


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