在Angular2中使用移动事件

时间:2016-03-01 16:40:09

标签: javascript-events typescript angular hammer.js

我想知道我是否可以获得有关移动设备事件的帮助。我正在寻找一种方法将函数绑定到Angular 2中的滑动事件。我在Github上的this issue中看到,Angular 2使用Hammer.js进行移动事件处理。

我遇到一些麻烦,因为我收到以下错误:

  

EXCEPTION:没有加载Hammer.js,无法绑定swipeleft事件

我的代码片段如下:

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.');
   }
 }

如果我将Hammer Gestures添加到我的构造函数中,我会收到此错误:

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

例外:没有提供者! (ColumnDirective - &gt; t)

对此问题的任何帮助将不胜感激!

6 个答案:

答案 0 :(得分:13)

经过大量的摆弄,我没有成功让Angular2的HammerGesturesPluginCommon工作(到目前为止)。受Bill Mayes回答的启发,我提交这个作为他的答案的详细说明,我能够开始工作(在Ipad mini和Android手机上测试)。

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

首先,在index.html文件的脚本标签中手动引用hammer.js(我也引用锤子时间来消除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);
        }

    }

这样,您只需要在任何特定元素上启用锤子手势时引用属性 hammer-gestures 注意:该元素似乎需要一个唯一的ID才能工作

答案 1 :(得分:7)

嗯,在OP之后很久,但是如果你只有简单的要求并且不想用hammer.js捣碎,这里是一个基本的水平狙击手。只需放入一个组件,然后添加自己的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);
          }
        }
      }
    } 
  }

答案 2 :(得分:3)

我有点犹豫要不要在我的应用程序中添加滑动手势,因为这里的答案似乎表明它会有点混乱。

  

EXCEPTION:没有加载Hammer.js,无法绑定swipeleft事件

只需加载hammer.js即可轻松处理此错误。无需自定义代码。

评论中提到的另一个错误似乎是从rc1开始修复的错误。

答案 3 :(得分:2)

我能够通过绕过内置的Hammer集成并运行我自己的工作来获得一些工作:

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');
        }
    }
}

答案 4 :(得分:1)

&#34; EXCEPTION:没有加载Hammer.js,无法绑定swipeleft事件&#34;因为锤子需要被包含在页面中而被提出。

实施例:     &lt; script src =&#34; node_modules / hammerjs / hammer.js&#34;&gt;&lt; / script&gt;

我已经阅读了有关如何使用有角度的锤子的所有其他答案,他们看起来很hacky。 默认情况下,HammerJs已禁用SwipeDown和SwipeUp方法。之前的所有答案都不是right2 typescript方式来解决手势问题或覆盖锤子的默认设置。 我花了大约4个小时挖掘angular2和hammerjs提交。

你在这里:

我们需要的第一件事是angular2的hammerjs打字。

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;
    }
}

我们需要做的最后一件事是打开我们的主要boostrap文件并将我们的自定义配置插入到boostrap方法中,如下所示:

// ... 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>

此拉取请求启用了覆盖默认设置,并为我提供了找到正确方法的起点:

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

答案 5 :(得分:0)

您需要添加

HelperServiceHammerGesturesPluginCommon提供商,可以在@Component(...)注释或bootstrap(AppComponent, [...])中删除错误&#34;没有提供商... &#34;

您是否在输入页面的某处为Hammer.js添加了脚本标记?