简体   繁体   中英

How to handle hybrid devices in click/touch events properly?

I'm trying to find out how to work with hybrid devices when it comes to binding touch and click events, but I can't find any solution that actually seems to work (I haven't got a hybrid device so I cannot test directly but since the failed attempts doesn't even work on normal devices I assume they don't work on a hybrid device either).

The problem is that on a hybrid device you have to cover both touch and click events without firing the functions twice. So if you look at my failed attempts (2 and 3) you can see that I bind to both touchend and click , but there appears to be some sort of syntax error or something because this causes none of the events to actually fire.

The first solution works fine but that's when I'm just using one or the other of the event firing types.

What I've tried so far:

1 - Works on touch devices and click devices:

_renderer.listenGlobal('document', 'ontouchstart' in window ? 'touchend' : 'click', (e) => {

  console.log('works');  
});

2 - Doesn't fire on either touch or click devices:

_renderer.listenGlobal('document', 'touchend click', (e) => {

  console.log('works');

  e.stopPropagation(); 
});

3 - Doesn't fire on either touch or click devices:

_renderer.listenGlobal('document', 'touchend, click', (e) => {

  console.log('works');  

  e.stopPropagation();
});

As you can see the first example covers 2/3 device types, while the other ones cover 0.

How can I make sure that my functions will run properly on every device?

You could use a Subject and debounce for a couple of milliseconds so you only have one event, something like this:

import {Component, Renderer} from '@angular/core'
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
  `,
})
export class App {
  name = 'Angular2';
  subject = new Subject();
  
  constructor(renderer: Renderer) {
    renderer.listenGlobal('document', 'touchend', (e) => {
      console.log('touchend');
      this.subject.next(e);
    });
    renderer.listenGlobal('document', 'click', (e) => {
      console.log('click');
      this.subject.next(e);
    });

    this.subject.debounceTime(100).subscribe(event => {
      console.log(event); //do stuff here
    })
  }
}

So when you use hybrid devices, you will get this: 在此处输入图片说明

Two events were fired, but you only get one on your Observable.

You can play around in this plunker

Just add (tap) directive instead of (click) directive on your components and add hammerjs to your index.html file.

Angular 2 will do all the job for you.

Example:

<my-component (tap)="doSomething()"></my-component>

On your index.html add:

<script src="hammer.min.js"></script>

To get hammerjs

npm install hammerjs --save

With this the click and the tap will work fine. If you want to have more control over the tap or you want to bind events to your element on runtime try something like this.

_hammerEvents: HammerManager;

public bindTapEvent(element: ElementRef):void{
    this._hammerEvents = new Hammer(element.nativeElement);
    this._hammerEvents.on("tap", (event:any) => { /* do something */});
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM