Использование мобильных событий в Angular2

Мне было интересно, могу ли я получить некоторую помощь в отношении событий для мобильных устройств. Я искал способ привязать функции для проведения событий в Angular 2. Я видел в этом эту проблему на Github, в которой упоминается, что Angular 2 использует Hammer.js для обработки мобильных событий.

У меня возникли проблемы с работой, потому что я получаю следующую ошибку:

ИСКЛЮЧЕНИЕ: 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) {}

ИСКЛЮЧЕНИЕ: Нет провайдера для t! (ColumnDirective → t)

Любая помощь с этой проблемой будет оценена!

Ответ 1

После долгих ворчаний, я не успел получить Angular2 HammerGesturesPluginCommon для работы (пока). Вдохновленный Биллом Мейсом, я представляю это как проработку его ответа, который я смог получить (проверенный на Ipad mini и Android-телефоне).

В принципе, мое решение выглядит следующим образом.

Во-первых, вручную ссылайтесь на hammer.js в тегах script вашего файла index.html(я также ссылаюсь на время молотка, чтобы исключить задержку в 300 мс):

Во-вторых, установите определения типов для 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, если вы хотите обнаружить вертикальные (вверх/вниз) swipes (левый/правый swipes по умолчанию, а не вертикальный). Дополнительные параметры можно найти здесь о hammer 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);
        }

    }

Таким образом вам нужно всего лишь ссылаться на атрибут жестов молотка, если вы хотите включить жесты молотка на любом конкретном элементе. Примечание: для работы для элемента требуется уникальный идентификатор.

Ответ 2

Хорошо, долго после OP, но если у вас есть только простые требования и вы не хотите гадать с hammer.js, вот базовый горизонтальный swiper. Просто зайдите в компонент и добавьте свои собственные функции doSwipeLeft и doSwipeRight.

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

Ответ 3

Я был немного нерешительным, чтобы добавить салфетки в мое приложение, потому что ответы здесь, казалось, предполагали, что это будет немного грязно.

ИСКЛЮЧЕНИЕ: Hammer.js не загружен, не может связывать событие swipeleft

С этой ошибкой легко справиться, просто загрузив hammer.js. Не требуется специальный код.

Другая ошибка, упомянутая в комментариях, по-видимому, была ошибкой, которая исправлена ​​с точки зрения rc1.

Ответ 4

Мне удалось получить что-то, работая в обход встроенной интеграции 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');
        }
    }
}

Ответ 5

"EXCEPTION: Hammer.js не загружен, не может связывать событие swipeleft" возникает потому, что hammerjs необходимо включить в страницу.

Пример:   < script src= "node_modules/hammerjs/hammer.js" > </script>

Я прочитал все остальные ответы о том, как использовать hammerjs с angular, и они выглядят взломанными. По умолчанию HammerJs отключил методы SwipeDown и SwipeUp. Все предыдущие ответы не являются правильными angular2 typescript способ решить проблему жестов или переопределить настройки по умолчанию для молотка. Мне потребовалось около 4 часов, чтобы копаться в angular2, а hammerjs совершает.

Здесь вы находитесь:

Первое, что нам понадобится, это hammerjs typings для angular2.

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

Далее нам нужно создать наш настраиваемый класс переопределения config. Этот класс может использоваться для переопределения всех настроек 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

Ответ 6

Вам нужно добавить

HelperService и HammerGesturesPluginCommon для поставщиков где-нибудь, в аннотации @Component(...) или в bootstrap(AppComponent, [...]), чтобы избавиться от ошибки "Нет провайдера для..."

Вы добавили тег script для Hammer.js где-то на вашей странице входа?