更新 : 2019-03-22

以前以为 hammer 的触发顺序是 parent -> child 和我们常用的 js 冒泡相反 .

今天才知道原来 hammer 根本没有冒泡或者捕获的概念,你先绑定哪一个事件它就触发哪一个. 晕 ~

hammer 还有一个看上去好像 bug 的问题

<div id="keat" class="keat">
<div id="left" class="left"></div>
<div id="right" class="right"></div>
</div>
const left = new Hammer(document.getElementById('left'));
left.on('panstart', (e: HammerInput) => console.log(e.target)); const keat = new Hammer(document.getElementById('keat'));
keat.on('panstart', (e: HammerInput) => console.log(e.target));

如果我们起始点是 left 然后 10px 后在 right, 这时 hammer 触发获取到的 e.target 会有 2 个.

left 获取到 left, keat 获取到 right

如果我们依赖 e.target 做判断要不要触发 event handler 可能就会遇到坑了.  目前没有办法解决. 我是想办法让用户避开这种交互.

更新 : 2019-03-12

double tap

var manager = new Hammer(el);
const tap = manager.get('tap');
manager.remove('tap'); var doubleTap = new Hammer.Tap({
event: 'doubletap',
taps: 2
}); manager.add([doubleTap, tap]); tap.requireFailure(doubleTap);
doubleTap.recognizeWith(tap); manager.on('doubletap', function (e) {
console.log('doubletap');
}); manager.on('tap', function (e) {
console.log('tap');
});

留意 manager.add array 的顺序, 反过来就不触发了.

double tap 和 tap 要互相认识一下. 因为彼此是有影响的.

更新 : 2018-01-31 (hammer 的坑)

hammer 的 pinch 在某种情况下会自动触发 panEnd,很奇葩.

解决方法就是记入时间呗

refer : https://github.com/hammerjs/hammer.js/issues/1134

hammer 有鬼, ghost click

如果你使用 pan + click 你会发现触发是这样的 panStart->panMove->panEnd->click

这个 browser 的行为有点不同

browser 是 mousedown -> mouseup -> click 或者 mousedown -> mousemove -> 没了

只要有 move click 事件是不会触发的.

所以这点要特别留意, 如果你不希望这个 ghost click 发生, hammer 也给出了方法

refer :

http://hammerjs.github.io/tips/

https://gist.github.com/jtangelder/361052976f044200ea17

就是在 click 时做一个判断.

另外提一个奇葩场景,如果你 bind 了 dragStart 然后 event.preventDefault 那么这个 ghostclick 是会被取消的, 但是 dragStart 是否每一次都会触发很难说 (我们看过 hammer 源码,不过我觉得它视乎动了点手脚).

更新 : 2018-01-18 

今天开发的时候遇到了一些奇葩形象.

看了看源码理清一下之前没有讲清楚的点

1. ng 有 3 个 Event Plugin (自己想扩展多几个是 ok 的), Dom Event Plugin, KeyBoard Event Plugin, HammerGesture Plugin

2. 所有的 plugin in 都必须在 app 级的 providers 去提供, lazy load 就迟了 (refer : https://github.com/angular/material2/issues/7905  and https://github.com/angular/angular/issues/19874)

3. angular material 的 MatSliderModule 会去覆盖 hammer 的 config ( 和我以前说到的方式是一样的 ) .

所以问题来了.

1. 你要 angular material 的 MatSliderModule 的手势 work good, 那么就一定要在 app 级注入这个模块, 或者提供它的手势 override 在 app providers (原因是上面第 2 条)

2. 如果你自己有一套 hammer config 逻辑, 那么注定会和 material 的 config 打架 ( 上面的 第 3 条 ), ng 只运行一个 hammer config

怎么破 ?

目前没有什么好方法. 大费周章的做法是, 开发一套 MyHammerGesture Plugin 并且把监听 (pan)="do()"  换成 (myPan)="do()"  这样就不会和它们打架咯.

material team 给出了一个方向

https://github.com/angular/material2/issues/4595

大致上就是他们以后会使用 service, 我个人觉得把 config 让出来给 app 是对的,如果我们写自己的库也应该自己封装 hammer 而不是用掉只有一个的 config.

更新 : 2017-12-28

hammer 的绑定流程是, 选择 element -> 实例化 hammer -> 设置 hammer (default 有些设置是关上的) -> 绑定监听事件.

pinch 和 rotate 设置默认是关上的, 想监听就要先打开设置, 这 2 个事件 hammer 会使用 css touch-action : none 来禁止游览器处理 touch (意思是说不能 scroll 了)

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

pan 和 swipe 默认设置是处理 horizontal 横向而已, 直的话是游览器的 scroll, touch-action : pan-y, 如果要监听多点就打开设置

hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL });
hammertime.get('swipe').set({ direction: Hammer.DIRECTION_VERTICAL });

以上是 hammer 的基本处理思路, 默认情况下让游览器可以 scroll. 要处理更多就自己设置吧.

ng 方面. 之前(看下面) 有提到过了. 所有的手势 ng 都会开启 hammer 的 pinch 和 rotate 设置, 也就是说即使你只是写了一个 (tap) 事件, 你的 element 就不能 scroll 了.

为什么 ng 要这样呢, 我也不知道. 可能懒得去理会吧. 全部开启设置, 才能统一方式绑定 (pinch) 和 (rotate) 嘛.

一直没有好的解决方法 ng 没什么接口方便我们覆盖这个逻辑

refer : https://medium.com/@TheLarkInn/creating-custom-dom-events-in-angular2-f326d348dc8b  (ng 自定义事件绑定)

ng 的 dom event 源码

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/dom_events.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/event_manager.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/hammer_gestures.ts

https://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/key_events.ts

几个方法参考 :

1. 直接调用 Hammer 不用 ng 的绑定

2. 覆盖 HammerGestureConfig.buildHammer 方法, 这个方法只能获取到 element, 所以我们通过在 element 上面写 data-need-rotate or data-need-pinch 之类的表达, 来实现不同情况下不同的 hammer 设置

3. 覆盖 HammerGesturesPlugin 来个统统重写...

我目前用了第 2 个 方案. 暂时挺着吧.

更新 22-08-2017

hammerjs 的事件有不同的设置 options

var myElement = document.getElementById('myElement');
var mc = new Hammer(myElement);
mc.get('pan').set({ direction: Hammer.DIRECTION_ALL });
mc.on("panleft panright panup pandown tap press", function(ev) {
myElement.textContent = ev.type +" gesture detected.";
});

pan 事件默认的 direction 是没有包含上下移动的, 那我们可以自己去设置它.

而 Angular 默认会帮我们把所有的 hammer 都设置一遍如下的代码

这 2 个设置会让所有的 hammer element 无法滚动. 这个要注意哦.

我们可以通过 overrides 去添加和覆盖上面的逻辑.

  providers: [{
provide: HAMMER_GESTURE_CONFIG,
useClass: MyHammerConfig
}] export class MyHammerConfig extends HammerGestureConfig {
overrides = <any>{
'pan': { direction : Hammer.DIRECTION_ALL }
}
}

大概这样就可以了,不过呢这个 config 是全局的. 目前我还没发放可以针对不同的 element 设置不同的 config .

可能需要直接调用 hammerjs 才可以了。

refer :

http://hammerjs.github.io/

https://bevacqua.github.io/dragula/

手机 和 PC 在交互体验上最大的区别是交互工具不同.

PC端,我们用滑鼠

手机端, 我们用触屏

滑鼠 vs 触屏

滑鼠有 hover 概念, 触屏没有.

触屏能多点 (多种手势), 滑鼠没有.

responsive design 解决了视觉上的差异问题,却没有解决交互上的差异问题.

hammerjs 帮我们解决的是滑鼠, 触屏之前的差异问题.

比如 : 监听各种手势, click 的 delay 300ms 问题, touchmove 模拟成 mousemove 事件等等.

angular 认可 hammerjs, 所以只要你 import hammerjs, 你可以直接这样写

<div (tap)="test()" >
test
</div>

angular 会使用 hammerjs 的方法来绑定 tap 事件. 很方便吧 ?

使用 npm 加载

  "dependencies": {
"hammer-timejs": "^1.1.0",
"hammer-touchemulator": "0.0.2",
"hammerjs": "^2.0.8",
},
"devDependencies": {
"@types/hammerjs": "^2.0.34",
}

在 main.ts 里 import 就可以啦

import 'hammerjs';
import 'hammer-timejs';
import * as TouchEmulator from 'hammer-touchemulator';
TouchEmulator();

TouchEmulator 是 development 情况下的才使用的.

手机还有一个问题就是在 drag and drop. 原生游览器的 drag and drop 在手机端支持的不好.

很多人会用 touchmove 来模拟. 也就是 hammerjs 里面的 pan 事件.

但是具体做法还是挺困难的.

因为触屏没有 hover 概念, 也没 touchover 事件, 所以当用户 pan 的时候你并没有办法轻易的监听 dragover 来处理事情. (比如你要做 sorting)

我在网上看了一些人的做法是通过 document.elementFromPoint(x,y) 来获取交会的节点或则每一次 pan 的时候都通过 service 发布事件, 然后其它组件监听, 在依据自己的 element.getBoundingClientRect 的

position 来确定是否 over 到了 element. 简单就说就是模拟 dragover 事件.

如果你有好方法欢迎你留意告诉我哦.

angular2 学习笔记 の 移动端开发 ( 手势 )的更多相关文章

  1. Qlik Sense学习笔记之Mashup开发(二)

    date: 2019-01-26 11:28:07 updated: 2019-01-26 11:28:07 Qlik Sense学习笔记之Mashup开发(二) 1.Mobile SPA UI Fr ...

  2. Qlik Sense学习笔记之Mashup开发(一)

    date: 2018-12-21 12:33:29 updated: 2018-12-21 12:33:29 Qlik Sense学习笔记之Mashup开发(一) 1.基于Qlik Sense API ...

  3. Android(java)学习笔记219:开发一个多界面的应用程序之两种意图

    1.两种意图: (1)显式意图: 在代码里面用intent设置要开启Activity的字节码.class文件: (2)隐式意图: Android(java)学习笔记218:开发一个多界面的应用程序之人 ...

  4. APPCAN学习笔记003---原生开发与HTML5技术

    APPCAN学习笔记003---原生开发与HTML5技术 技术qq交流群:JavaDream:251572072 1.HTML5的优势:   HTML5强悍牢固的骨架   CSS3精致到每一个毛孔的皮 ...

  5. APPCAN学习笔记001---app高速开发AppCan.cn平台概述

    1.APPCAN学习笔记---app高速开发AppCan.cn平台概述 1. 平台概述 技术qq交流群:JavaDream:251572072 AppCan.cn开发平台是基于HTML5技术的跨平台移 ...

  6. Hadoop学习笔记(4) ——搭建开发环境及编写Hello World

    Hadoop学习笔记(4) ——搭建开发环境及编写Hello World 整个Hadoop是基于Java开发的,所以要开发Hadoop相应的程序就得用JAVA.在linux下开发JAVA还数eclip ...

  7. Android(java)学习笔记162:开发一个多界面的应用程序之两种意图

    1.两种意图: (1)显式意图: 在代码里面用intent设置要开启Activity的字节码.class文件: (2)隐式意图: Android(java)学习笔记218:开发一个多界面的应用程序之人 ...

  8. jsp学习笔记:mvc开发模式

    jsp学习笔记:mvc开发模式2017-10-12 22:17:33 model(javabe)与view层交互 view(视图层,html.jsp) controller(控制层,处理用户提交的信息 ...

  9. angular2 学习笔记 ( server-side rendering, angular universal, 服务端渲染 )

    更新 : 2018-01-10  大半年过去了依然没有做 server side render 的冲动,但是一直有关注这方便的做法. 今天领悟了一些道理, 这里做个记入. server side re ...

随机推荐

  1. handsontable 属性汇总

    常规属性: 1.固定行列位置 fixedRowsTop:行数 //固定顶部多少行不能垂直滚动 fixedColumnsLeft:列数 //固定左侧多少列不能水平滚动 2.拖拽行头或列头改变行或列的大小 ...

  2. Lintcode212 Space Replacement solution 题解

    [题目描述] Write a method to replace all spaces in a string with%20. The string is given in a characters ...

  3. 在VMWare上安装Arch Linux

    1.为什么选择Arch Linux Arch Linux 是通用 x86-64 GNU/Linux 发行版.Arch采用滚动升级模式,尽全力提供最新的稳定版软件.初始安装的Arch只是一个基本系统,随 ...

  4. vue组件利用formdata图片预览以及上传《转载》

    转载修改 在项目中直接新建一个单文件页,复制一下代码即可       upload组件: <template> <div class="vue-uploader" ...

  5. JavaSE语法基础(3)---函数、数组

    JavaSE语法基础(3)---函数.数组 函数的概念:实现特定功能的一段代码,可反复使用. 函数的出现减少代码冗余,提高代码的复用性,可读性,可维护性,可以使每个功能模块独立起来,方便分工合作. 函 ...

  6. linux scp 命令

    scp 命令 scp 命令 意思是 secure copy 即安全拷贝,可以把它看做是 cp 命令的高级版,可以跨主机拷贝. 经常用来在局域网内不同主机之间分享文件,或者在本机与远程主机中分享文件. ...

  7. Eclipse项目中web app libraries和 Referenced Libraries区别

    Referenced  Libraries是编译环境下使用的JAR包,所谓编译环境下使用的JAR包, 就是说你在Eclipse中进行源文件的编写的时候,所需要引用到的类都从Referenced  Li ...

  8. CSS选取第n个标签元素

    最近做一个项目,碰到这样的需求,需要选取某个元素的倒数第几个标签元素,想让他显示不同的样式 1.first-child first-child表示选择列表中的第一个标签.例如:li:first-chi ...

  9. 跨平台原生AR/VR应用研发引擎-NVisionXR开放内测

      NVisionXR引擎正式开放内测.现在,对原生AR/VR应用开发有兴趣的企业和开发者均可通过NVisionXR官网(www.nvisionxr.com)申请试用. NVisionXR引擎介绍视频 ...

  10. 4c语言的第0次作业

    1.你认为大学的学习生活.同学关系.师生关系应该是怎样? 我认为大学的学习生活应该是充实有意义的,有对学习的激情又有与伙伴相知的愉悦. 我认为同学关系应该是互相尊重,互相学习,坦诚相待. 我认为师生关 ...