2016-03-01 65 views
9

我想知道是否可以獲得關於移動設備事件的一些幫助。我正在四處尋找一種方法來綁定函數以刷新Angular 2中的事件。我在Github的this issue中看到,提到Angular 2使用Hammer.js進行移動事件處理。在Angular2中使用移動事件

我有一些麻煩的情況下工作,因爲我得到以下錯誤:

EXCEPTION: Hammer.js is not loaded, can not bind swipeleft event

我的代碼片段低於:

import {Component, View, AfterContentInit} from 'angular2/core'; 
import {HelperService} from "./helper-service"; 
import {HammerGesturesPluginCommon} from 'angular2/src/platform/dom/events/hammer_common' 

@View({ 
    template: `<div [id]="middleCircle" (swipeleft)="doThis()"></div>` 
}) 

export class ColumnDirective implements AfterContentInit { 
    constructor(private helperService:HelperService) {} 
    doThis(){ 
    console.log('This thing has been done.'); 
    } 
} 

如果我在錘手勢添加我的構造函數,我得到這個錯誤:

constructor(private helperService:HelperService, private hammerGesturesPluginCommon: HammerGesturesPluginCommon) {} 

EXCEPTION: No provider for t! (ColumnDirective -> t)

任何有關這個問題的幫助,將不勝感激!

+0

我剛剛發現這個線程,因爲我試圖實現相同的事情。如果我找到任何東西,會讓你知道。 –

+0

我通過爲我的index.html(我正在使用angular 2種子項目)添加一個用於hammer.js的腳本標記,能夠通過「Hammer.js未加載」,但是當我觸發滑動時,現在得到一個以「EXCEPTION:RangeError:超出最大調用堆棧大小」開始的巨大錯誤列表。 –

+0

是啊@BillyMayes現在同樣的問題。 –

回答

13

很多擺弄之後,我沒有成功獲得Angular2的HammerGesturesPluginCommon工作(到目前爲止) 。受Bill Mayes回答的啓發,我提交這個作爲他的答案的闡述,我能夠工作(在Ipad mini和Android手機上測試)。

基本上,我的解決方案如下。

首先,手動參考hammer.js在您的index.html文件的腳本標籤(我還引用了錘的時間來消除300ms的延遲):

其次,安裝hammerjs的類型定義(tsd install hammerjs -save)。然後,你可以可以創建一個Angular2 attibute指令是這樣的:

/// <reference path="./../../../typings/hammerjs/hammerjs.d.ts" /> 
import {Directive, ElementRef, AfterViewInit, Output, EventEmitter} from 'angular2/core'; 
@Directive({ 
    selector: '[hammer-gestures]' 
}) 
export class HammerGesturesDirective implements AfterViewInit { 
    @Output() onGesture = new EventEmitter(); 
    static hammerInitialized = false; 
    constructor(private el: ElementRef) { 

    } 
    ngAfterViewInit() { 

     if (!HammerGesturesDirective.hammerInitialized) { 

      let hammertime = new Hammer(this.el.nativeElement); 
      hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL }); 
      hammertime.on("swipeup", (ev) => { 
       this.onGesture.emit("swipeup"); 
      }); 
      hammertime.on("swipedown", (ev) => { 
       this.onGesture.emit("swipedown"); 
      }); 
      hammertime.on("swipeleft", (ev) => { 
       this.onGesture.emit("swipeleft"); 
      }); 
      hammertime.on("swiperight", (ev) => { 
       this.onGesture.emit("swiperight"); 
      }); 
      hammertime.on("tap", (ev) => { 
       this.onGesture.emit("tap"); 
      }); 

      HammerGesturesDirective.hammerInitialized = true; 
     } 


    } 
} 

您需要設置Hammer.DIRECTION_ALL如果要檢測垂直(上/下)刷卡(左/右揮筆爲默認值,不是垂直的)。更多選擇,可以發現有關錘API這裏:http://hammerjs.github.io/api/#hammer

最後,在你的父組件,你可以做這樣的事情:

import {Component} from "angular2/core"; 
import {HammerGesturesDirective} from "./path/HammerGesturesDirective"; 

    @Component({ 
     selector: "my-ng2-component", 
     template: `<div style='width:100px; height: 100px;background-color: red' 
      (onGesture)="doSwipe($event)" hammer-gestures></div>`, 
     directives: [HammerGesturesDirective] 

    }) 
    export class MyNg2Component { 
     constructor() { } 

     doSwipe(direction: string) { 
      alert(direction); 
     } 

    } 

這樣,你只需要引用屬性錘手勢當你想在任何特定的元素上啓用錘手勢。 注意:該元素似乎需要一個唯一的ID來工作

+2

我還沒有測試過,但我非常喜歡這個主意,我在辦公室裏大聲說「很酷」。它看起來很乾淨 –

+0

很好地解釋了答案:) +1 –

+0

我發現將此指令添加到我的組件中的多個元素中,由於靜態的'hammerInitialized'屬性,只有第一個元素被連接起來。我取消了支票,它似乎對我更好。 (大聲「酷」也)。 – GaryB96

0

您需要添加

HelperServiceHammerGesturesPluginCommon到某處供應商,無論是在@Component(...)註釋或bootstrap(AppComponent, [...])擺脫錯誤的「無提供者......」

你添加腳本Hammer.js的標籤在您的輸入頁面的某處?

+0

我在我的'@ Component'中添加了'providers:[HammerGesturesPluginCommon]',並且在一個cdn腳本標記中包含了Hammer.js,現在我得到的調用堆棧大小已經超出了,看起來就像我們離得更近! –

+0

也許https://github.com/angular/angular/issues/5964或https://github.com/angular/angular/issues/5964提供了一些信息。從我記得的是不明確地添加'zone.js'(我自己沒有遇到這個問題,只記得看到討論,我不知道這是否仍然是最新的)。也可能是腳本標記順序的問題。 –

2

我能夠繞過得到的東西的工作內置錘集成和運營自己:

import { Component, ElementRef, AfterViewInit } from 'angular2/core'; 

@Component({ 
    selector: 'redeem', 
    templateUrl: './redeem/components/redeem.html' 
}) 
export class RedeemCmp implements AfterViewInit { 

    static hammerInitialized = false; 

    constructor(private el:ElementRef) { } 

    ngAfterViewInit() { 
     console.log('in ngAfterViewInit'); 
     if (!RedeemCmp.hammerInitialized) { 
      console.log('hammer not initialised'); 

      var myElement = document.getElementById('redeemwrap'); 
      var hammertime = new Hammer(myElement); 
      hammertime.on('swiperight', function(ev) { 
       console.log('caught swipe right'); 
       console.log(ev); 
      }); 

      RedeemCmp.hammerInitialized = true; 
     } else {    
      console.log('hammer already initialised'); 
     } 
    } 
} 
+0

這似乎是一個更好的主意。由於我們仍處於測試階段,因此很多事情仍然很麻煩。謝謝您的幫助! –

+0

@BillMayes非常感謝。我在下面詳細說明了你的回答。 – brando

+0

使用RC1它說Hammer它在'var hammertime = new Hammer(myElement)'給出了我的錯誤;' - Hammer沒有定義。任何想法在RC1中改變了什麼? – LorDex

3

我對我的應用程序添加滑動手勢有點猶豫,因爲這裏的答案似乎表明它會有點混亂。

EXCEPTION: Hammer.js is not loaded, can not bind swipeleft event

這個錯誤很容易通過加載hammer.js來處理。不需要自定義代碼。

評論中提到的其他錯誤似乎是一個固定爲rc1的錯誤。

1

「EXCEPTION:Hammer.js未加載,無法綁定swipeleft事件」被引發,因爲需要將hammerjs包含在頁面中。

例子: <腳本SRC = 「node_modules/hammerjs/hammer.js」 > < /腳本>

我已閱讀有關如何使用角度使用hammerjs所有其他的答案,他們看起來哈克。 默認情況下,HammerJs禁用了SwipeDown和SwipeUp方法。以前的所有答案都不是正確的angular2打字方式來解決手勢問題或覆蓋錘子的默認設置。 我花了大約4個小時挖掘angular2和hammerjs提交。

給你:

,我們將需要的是hammerjs分型爲angular2第一件事。

typings install github:DefinitelyTyped/DefinitelyTyped/hammerjs/hammerjs.d.ts#de8e80dfe5360fef44d00c41257d5ef37add000a --global --save 

接下來我們需要創建我們的自定義覆蓋配置類。 該類可用於覆蓋所有默認的hammerjs和angular2 hammerjs配置設置。

hammer.config.ts:

import { HammerGestureConfig } from '@angular/platform-browser'; 
import {HammerInstance} from "@angular/platform-browser/src/dom/events/hammer_gestures"; 


export class HammerConfig extends HammerGestureConfig { 

    buildHammer(element: HTMLElement): HammerInstance { 
     var mc = new Hammer(element); 

     mc.get('pinch').set({ enable: true }); 
     mc.get('rotate').set({ enable: true }); 

     mc.add(new Hammer.Swipe({ direction: Hammer.DIRECTION_ALL, threshold: 0 })); 

     for (let eventName in this.overrides) { 
      mc.get(eventName).set(this.overrides[eventName]); 
     } 

     return mc; 
    } 
} 

,我們需要做的最後一件事,就是打開我們的主要的自舉文件,並插入我們的自定義配置爲自舉方法是這樣的:

// ... other imports ... 
import { HammerConfig } from './shared/hammer.config'; 

bootstrap(AppComponent, [ 
    provide(HAMMER_GESTURE_CONFIG, { useClass: HammerConfig }) 
]); 

現在,在我們的應用中可以使用swipeDown和swipeUp

<div class="some-block" (swipeDown)="onSwipeDown"></div> 

這拉動請求啓用OVERR默認設置iding,給我的出發點,以找到正確的方法:

https://github.com/angular/angular/pull/7924

5

好,長的OP後,但如果你只得到了簡單的要求,不想hammer.js渣土,這裏是一個基本的水平sw。。只需放入一個組件並添加您自己的doSwipeLeftdoSwipeRight函數。

touch1 = {x:0,y:0,time:0}; 

    @HostListener('touchstart', ['$event']) 
    @HostListener('touchend', ['$event']) 
    //@HostListener('touchmove', ['$event']) 
    @HostListener('touchcancel', ['$event']) 
    handleTouch(ev){ 
    var touch = ev.touches[0] || ev.changedTouches[0]; 
    if (ev.type === 'touchstart'){ 
     this.touch1.x = touch.pageX; 
     this.touch1.y = touch.pageY; 
     this.touch1.time = ev.timeStamp; 
    } else if (ev.type === 'touchend'){ 
     var dx = touch.pageX - this.touch1.x; 
     var dy = touch.pageY - this.touch1.y; 
     var dt = ev.timeStamp - this.touch1.time; 

     if (dt < 500){ 
     // swipe lasted less than 500 ms 
     if (Math.abs(dx) > 60){ 
      // delta x is at least 60 pixels 
      if (dx > 0){ 
      this.doSwipeLeft(ev); 
      } else { 
      this.doSwipeRight(ev); 
      } 
     } 
     } 
    } 
    }