【问题标题】:What is the best way to implement swipe navigation in Angular 2?在 Angular 2 中实现滑动导航的最佳方式是什么?
【发布时间】:2017-07-24 08:20:03
【问题描述】:

我是 Angular 2 的新手,正在寻找一种方法来为移动用户实现良好的标签触摸滑动导航,并通过滑动过渡到下一个标签视图。

到目前为止,我发现了一个名为 angular2-useful-swiper 的包,虽然我并不热衷于使用它,因为我最终会提前初始化我的组件,即使它们不在视图中。

有人知道为 Angular 2 实现基于标签滑动的导航的好方法吗?任何反馈将不胜感激。 :)

【问题讨论】:

    标签: angular navigation swipe-gesture


    【解决方案1】:

    对于滑动检测,这里是比添加 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 对象。所以选择一些文本会强制导航到下一页...

    【讨论】:

    • 我在hammer.js github上的一个bug问题中发布了你的解决方案,希望他们能在我们使用它的问题上做出反应......
    • 这是一个非常轻量级且很棒的解决方案,只有一个小漏洞是,如果您在一个旁边双击(如弹奏键盘),它会将其检测为滑动。
    【解决方案2】:

    你可以使用HammerJS来实现触摸动作,你可以按照这个plunker为例。

    包含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 link for example

    要实现标签angular2-material 是一个不错的起点,请关注this link

    【讨论】:

      【解决方案3】:

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

      $ npm install hammerjs hammer-timejs
      

      然后将导入添加到“app.module.ts”,以便使用/捆绑它们:

      import 'hammerjs';
      import 'hammer-timejs';
      

      现在您可以处理动作的事件:
      旋转

      新闻

      点击
      滑动

      例如你可以说:

      &lt;li *ngFor="let employee of employeesList;" (swiperight)="myswiperight(employee)" (swipeleft)="myswipeleft(employee)"&gt;

      或者:

      &lt;div (panstart)="onPanStart($event)" (panmove)="onPan($event)"&gt;

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

      【讨论】:

        【解决方案4】:

        我根据@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>
        

        【讨论】:

          【解决方案5】:

          我设法想出了一个一次写入,随处使用的函数类型,我将它放在一个名为“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。我刚刚提出了更高级别的抽象,这对我来说更有意义。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-27
            • 2017-02-09
            • 1970-01-01
            • 2010-12-14
            相关资源
            最近更新 更多