SNS项目笔记<六>--手势Gestures

2018-09-12 15:41:15 浏览数 (1)

移动开发与PC开发大相径庭,PC上最多的是鼠标点击事件,但是手机上面的手势事件却又很多,最常见的开发问题是处理父控件与子控件事件冲突问题,这就要我们十分了解手势了。ionic使用的是angular的库,用hammer来解决移动端的屏幕手势。

1、angular处理事件源码:

这里直接贴上angular源码地址:angular源码之hammer_gestures <这里方便它更新后的修改> 这里又贴上该地址的源码以便说明:

代码语言:javascript复制
/**
 * @license
 * Copyright Google Inc. All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

import {Inject, Injectable, InjectionToken} from '@angular/core';

import {DOCUMENT} from '../dom_tokens';

import {EventManagerPlugin} from './event_manager';

const EVENT_NAMES = {
  // pan
  'pan': true,
  'panstart': true,
  'panmove': true,
  'panend': true,
  'pancancel': true,
  'panleft': true,
  'panright': true,
  'panup': true,
  'pandown': true,
  // pinch
  'pinch': true,
  'pinchstart': true,
  'pinchmove': true,
  'pinchend': true,
  'pinchcancel': true,
  'pinchin': true,
  'pinchout': true,
  // press
  'press': true,
  'pressup': true,
  // rotate
  'rotate': true,
  'rotatestart': true,
  'rotatemove': true,
  'rotateend': true,
  'rotatecancel': true,
  // swipe
  'swipe': true,
  'swipeleft': true,
  'swiperight': true,
  'swipeup': true,
  'swipedown': true,
  // tap
  'tap': true,
};

/**
 * A DI token that you can use to provide{@link HammerGestureConfig} to Angular. Use it to configure
 * Hammer gestures.
 *
 * @experimental
 */
export const HAMMER_GESTURE_CONFIG = new InjectionToken<HammerGestureConfig>('HammerGestureConfig');

export interface HammerInstance {
  on(eventName: string, callback?: Function): void;
  off(eventName: string, callback?: Function): void;
}

/**
 * @experimental
 */
@Injectable()
export class HammerGestureConfig {
  events: string[] = [];

  overrides: {[key: string]: Object} = {};

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

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

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

    return mc;
  }
}

@Injectable()
export class HammerGesturesPlugin extends EventManagerPlugin {
  constructor(
      @Inject(DOCUMENT) doc: any,
      @Inject(HAMMER_GESTURE_CONFIG) private _config: HammerGestureConfig) {
    super(doc);
  }

  supports(eventName: string): boolean {
    if (!EVENT_NAMES.hasOwnProperty(eventName.toLowerCase()) && !this.isCustomEvent(eventName)) {
      return false;
    }

    if (!(window as any).Hammer) {
      throw new Error(`Hammer.js is not loaded, can not bind ${eventName} event`);
    }

    return true;
  }

  addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
    const zone = this.manager.getZone();
    eventName = eventName.toLowerCase();

    return zone.runOutsideAngular(() => {
      // Creating the manager bind events, must be done outside of angular
      const mc = this._config.buildHammer(element);
      const callback = function(eventObj: HammerInput) {
        zone.runGuarded(function() { handler(eventObj); });
      };
      mc.on(eventName, callback);
      return () => mc.off(eventName, callback);
    });
  }

  isCustomEvent(eventName: string): boolean { return this._config.events.indexOf(eventName) > -1; }
}

源码上的手势都可以这样来使用:

代码语言:javascript复制
// html:
<ion-item (xxx)=method($event)></ion-item>

// ts:
method(event){ //TODO ideal }

即通过dom绑定来绑定一个处理事件的方法。

源码中跟我们划分好了有pan【随手指移动跟随事件】、pinch【双手指捏合事件】、press【长按事件】、rotate【手势翻转事件】、swipe【手指迅速滑动事件】、tap【短时间触摸事件】

这里说明各大事件是使用场景:pinch事件是在图片放大缩小的时候,拇指与食指进行缩放操作就可以使用pinch事件来实现,pan事件与swipe事件可以用来处理左右滑动等问题,rotate可以使用来实现使用操作杆等3D手势,tap可以代替点击click事件,press就不用详细说明了,大家都懂。

2、实际运用手势来处理事件冲突

错误写法1
代码语言:javascript复制
//html
<ion-item (tap)=parentClick($event)>
      <button  ion-button block (click)="childClick($event)">子控件点击</button>
</ion-item>

此时父控件手势完全遮盖住了子控件,造成button点击无效。

错误写法2
代码语言:javascript复制
//html
<ion-item (tap)=parentClick($event)>
      <button  ion-button block (tap)="childClick($event)">子控件点击</button>
</ion-item>

//html
<ion-item (click)=parentClick($event)>
      <button  ion-button block (click)="childClick($event)">子控件点击</button>
</ion-item>

这是我们常见的写法,两个同时用click或者tap来完成点击事件的处理,在实际操作中造成事件冒泡,点击button,两个方法同时运行。

正确写法
代码语言:javascript复制
//html
<ion-item (click)=parentClick($event)>
      <button  ion-button block (tap)="childClick($event)">子控件点击</button>
</ion-item>

由于错误写法1我们了解到,tap事件是触摸事件,并不是点击事件,在触发的时候会隔离事件冒泡,虽然不能一起使用,但是可以在click事件上阻止click触发,所以我们在子控件上使用tap,父控件上使用click,这样可以让我们的时间冒泡问题得以解决。

附上angular语法防止事件冒泡的文章: angular4 防止事件冒泡

timg.jpeg

0 人点赞