JS手势框架 —— Hammer.js

一、hammer.js简介

hammerJS是一个开源的,轻量级的触屏设备javascript手势库,它可以在不需要依赖其他东西的情况下识别触摸,鼠标事件。允许同时监听多个手势、自定义识别器,也可以识别滑动方向。

二、事件

1、Rotate事件:在指定的dom区域内,当两个手指或更多手指成圆型旋转时触发(就像两个手指拧螺丝一样)。该事件分别对以下事件进行监听并处理:

Rotatestart:旋转开始;Rotatemove:旋转过程;Rotateend:旋转结束;Rotatecancel:旋转取消

2、Pinch事件:在指定的dom区域内,两个手指(默认为两个手指,多指触控需要单独设置)或多个手指相对(越来越近)移动或相向(越来越远)移动时事件。该事件事以分别对以下事件进行监听并处理:

Pinchstart:多点触控开始;Pinchmove:多点触控过程;Pinchend:多点触控结束;Pinchcancel:多点触控取消;Pinchin:多点触控时两手指距离越来越近;Pinchout:多点触控时两手指距离越来越远

3、Press事件:在指定的dom区域内触屏版本的点击事件,这个事件相当于PC端的Click事件,该不能包含任何的移动,最小按压时间为500毫秒,常用于我们在手机上用的“复制、粘贴”等功能。该事件分别对以下事件进行监听并处理:

Pressup:点击事件离开时触发

4、Pan事件:在指定的dom区域内,一个手指放下并移动事件,即触屏中的拖动事件。这个事件在屏触开发中比较常用,如:左拖动、右拖动等,如手要上使用QQ时向右滑动出现功能菜单的效果。该事件还可以分别对以下事件进行监听并处理:

Panstart:拖动开始;Panmove:拖动过程;Panend:拖动结束;Pancancel:拖动取消;Panleft:向左拖动;Panright:向右拖动;Panup:向上拖动;Pandown:向下拖动

5、Tap事件:在指定的dom区域内,一个手指轻拍或点击时触发该事件(类似PC端的click)。该事件最大点击时间为250毫秒,如果超过250毫秒则按Press事件进行处理。

6、Swipe事件:在指定的dom区域内,一个手指快速的在触屏上滑动。即我们平时用到最多的滑动事件。

Swipeleft:向左滑动;Swiperight:向右滑动;Swipeup:向上滑动;Swipedown:向下滑动

三、使用方式

//创建一个新的hammer对象并且在初始化时指定要处理的dom元素

var hammertime = new Hammer(document.getElementById("test"));

//为该dom元素指定触屏移动事件

hammertime.on("pan", function (ev) {

//控制台输出

console.log(ev);

});

四、应用实例

对图片进行拖动、缩放和旋转操作(用到hammerJS中的事件Pan、Pinch和Rotate

核心代码:

var reqAnimationFrame = (function () {
  return window[Hammer.prefixed(window, 'requestAnimationFrame')] || function (callback) {
    window.setTimeout(callback, 1000 / 60);
  };
})();

var el = document.querySelector("#imgid");

var START_X = Math.round((window.innerWidth - el.offsetWidth) / 2);
var START_Y = Math.round((window.innerHeight - el.offsetHeight) / 2);

var ticking = false;
var transform; //图像效果
var timer;
var initAngle = 0; //旋转角度
var initScale = 1; //放大倍数

var mc = new Hammer.Manager(el); //用管理器 可以同时触发旋转 拖拽 移动
//var mc = new Hammer(el); //旋转和移动互斥
/**
ev.srcEvent.type touchstart touchend touchmove
ev.deltaX 手势移动位移变量
*/
mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
mc.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(mc.get('pan'));
mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get('pan'), mc.get('rotate')]);
//结束时做一些处理
mc.on("hammer.input", function(ev) {
  if(ev.isFinal) {
    console.log(START_X+" "+transform.translate.x +" "+ev.deltaX);
    START_X = transform.translate.x ;
    START_Y = transform.translate.y ;
}

});
mc.on("panstart panmove", onPan);
mc.on("rotatestart rotatemove rotateend", onRotate);
mc.on("pinchstart pinchmove", onPinch);
/**
第二次进入拖拽时 delta位移重置
移动时 初始位置startxy不动。delta增加
*/
function onPan(ev){
  if(!ev.isFinal) {
    el.className = '';
    console.log(START_X +" "+ START_Y +" | "+ev.deltaX +" "+ ev.deltaY);
   transform.translate = {
     x: START_X + ev.deltaX,
     y: START_Y + ev.deltaY
   };
   requestElementUpdate();
  }
}

function onPinch(ev){
  if(ev.type == 'pinchstart') {
    initScale = transform.scale || 1;
  }
  el.className = '';
  transform.scale = initScale * ev.scale;
  requestElementUpdate();
}

//旋转相关
var preAngle =0 ;
var tempAngleFlag=0;
var deltaAngle = 0;
var startRotateAngle = 0;

function onRotate(ev) {
  //点下第二个触控点时触发
  if(ev.type == 'rotatestart') {
    startRotateAngle = ev.rotation ;
    tempAngleFlag = 0 ;
  }
  if(ev.type == 'rotatemove'){
    if(tempAngleFlag == 0){
      preAngle = startRotateAngle;
      tempAngleFlag ++;
    }else{
      deltaAngle = ev.rotation - preAngle;
      el.className = '';
      transform.rz = 1; //非0 垂直xy轴
      transform.angle =initAngle + deltaAngle;
      requestElementUpdate();
    }
  }

  //旋转结束 记录当前图片角度
  if(ev.type =='rotateend'){
  initAngle = transform.angle;
  }
}

function updateElementTransform() {
  var value = [
'translate3d(' + transform.translate.x + 'px, ' + transform.translate.y + 'px, 0)',
'scale(' + transform.scale + ', ' + transform.scale + ')',
'rotate3d('+ transform.rx +','+ transform.ry +','+ transform.rz +','+ transform.angle + 'deg)'
];

value = value.join(" ");
  el.style.webkitTransform = value; /*为Chrome/Safari*/
  el.style.mozTransform = value; /*为Firefox*/
  el.style.transform = value; /*IE Opera?*/
  ticking = false;
}

function requestElementUpdate() {
  if(!ticking) {
    reqAnimationFrame(updateElementTransform);
    ticking = true;
  }
}

/**
初始化设置
*/
function resetElement() {

el.className = 'animate';
  transform = {
    translate: { x: START_X, y: START_Y },
    scale: 1,
    angle: 0,
    rx: 0,
    ry: 0,
    rz: 0
  };
  requestElementUpdate();
}

resetElement();

DEMO演示

五、注意事项

  1. 试着避免垂直方向上的 pan/swipe

垂直方向上的平移操作一般是用来滚动页面的,而且有些(过时的)浏览器不会传递事件,导致Hammer无法识别这些手势。

  1. 在设备上做测试

有时候Hammer需要做一些调整,像swipe的速率或其它阈值,如果你在一台反应较慢的设备上做测试,那么你要保证你的回调越简单越好。

  1. 去掉Windows Phone点击时的高亮效果

在Windows Phone上的IE10和IE11里tap某元素时,会有一个小小的tap高亮效果,加上这个meta标签可以取消这种效果:

  1. 选择不了文本

Hammer设置了一个属性用来提升桌面平移操作的用户体验(UX)。常规来说,当你在桌面级浏览器上拖动页面时,你应该是可以正常选中文本的,但user-select这个CSS属性禁用了这功能。如果你在意文本选择功能,同时觉得桌面级的体验没必要太尽善尽美,你可以很轻松地取消这个默认选项——确保在创建实例之前执行:

delete Hammer.defaults.cssProps.userSelect;

5.在tap之后,导致触发了一个click事件

这种click事件我们称之为一个“幽灵点击”事件,可创建了一个小函数来避免触摸后导致click。

六、浏览器/终端的支持

Harmmer可以运行在除了IE8及其以下的任何浏览器。浏览器若对触摸行为(touch-action)提供原生支持,那么对比那些不支持HarmmerJS某些事件的浏览器,将会有更好的体验。

H5案例分享:JS手势框架 —— Hammer.js的更多相关文章

  1. 移动端手势库Hammer.js学习

    感觉移动端原生支持的 touch.tap.swipe 几个事件好像还不够用,某些时候还会用到诸如缩放.长按等其他功能. 近日学习了一个手势库 Hammer.js,它是一个轻量级的触屏设备手势库,能识别 ...

  2. H5案例分享:使用JS判断客户端、浏览器、操作系统类型

    使用JS判断客户端.浏览器.操作系统类型 一.JS判断客户端类型 JS判断客户端是否是iOS或者Android手机移动端 通过判断浏览器的userAgent,用正则来判断手机是否是ios和Androi ...

  3. 移动端手势事件 hammer.JS插件

                      一.引入hammer.JS 1.下载地址:http://download.csdn.net/detail/webxiaoma/9872249 2.官网地址:http ...

  4. 强大的 Node.js Web 框架 - Daze.js

    去年年初对 Node.js 比较感兴趣,也用了很多 Node.js 的框架,但是开发体验不是特别好,我之前也是后端转前端,然后再接触 Node.js ,所以用过挺多的服务端框架,相对js而言,设计一款 ...

  5. H5案例分享:移动端touch事件判断滑屏手势的方向

    移动端touch事件判断滑屏手势的方向 方法一 当开始一个touchstart事件的时候,获取此刻手指的横坐标startX和纵坐标startY: 当触发touchmove事件时,在获取此时手指的横坐标 ...

  6. H5案例分享:移动端滑屏 touch事件

    移动端滑屏 touch事件 移动端触屏滑动的效果的效果在电子设备上已经被应用的越来越广泛,类似于PC端的图片轮播,但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch ...

  7. H5案例分享:html5移动开发细微之美

    html5移动开发细微之美 1.H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 <meta name="viewport" content="width=dev ...

  8. H5案例分享:html5重力感应事件

    html5重力感应事件 一.手机重力感应图形分析 1.设备围绕z轴的旋转角度为α,α角度的取值范围在[0,360). 设备在初始位置,与地球(XYZ)和身体(XYZ)某个位置对齐. 设备围绕z轴的旋转 ...

  9. Hammer.js移动端触屏框架的使用

    hammer.js是一个多点触摸手势库,能够为网页加入Tap.Double Tap.Swipe.Hold.Pinch.Drag等多点触摸事件,免去自己监听底层touchstart.touchmove. ...

随机推荐

  1. 从BSP模型到Apache Hama

    一.什么是BSP模型 概述 BSP(Bulk Synchronous Parallel,整体同步并行计算模型)是一种并行计算模型,由英国计算机科学家Viliant在上世纪80年代提出.Google发布 ...

  2. [bzoj2588][count on a tree] (主席树+lca)

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...

  3. [LeetCode] First Bad Version 第一个坏版本

    You are a product manager and currently leading a team to develop a new product. Unfortunately, the ...

  4. [LeetCode] Climbing Stairs 爬梯子问题

    You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...

  5. ConcurrentHashMap内存泄漏问题

    问题背景 上周,同事写了一段ConcurrentHashMap的测试代码,说往map里放了32个元素就内存溢出了,我大致看了一下他的代码及运行的jvm参数,觉得很奇怪,于是就自己捣鼓了一下.首先上一段 ...

  6. OpenCV二值图像孔洞填充的一个简单方法

    在Matlab下,使用imfill可以很容易的完成孔洞填充操作,感觉这是一个极为常用的方法,然而不知道为什么OpenCV里面却没有集成这个函数.在网上查了好多关于Opencv下的孔洞填充方法,大部分使 ...

  7. setTimeout和setInterval定时器使用详解测试

    var len=4; while(len--){ var time=setTimeout(function(){ console.log(len); },0); console.log(time); ...

  8. [bzoj1670][Usaco2006 Oct]Building the Moat

    Description 为了防止口渴的食蚁兽进入他的农场,$Farmer John$决定在他的农场周围挖一条护城河.农场里一共有$N$股泉水,并且,护城河总是笔直地连接在河道上的相邻的两股泉水.护城河 ...

  9. smarty使用

    smarty-牛刀小试 smarty 初识 官网 http://www.smarty.net/ Smarty is a template engine for PHP(PHP模板引擎) smarty使 ...

  10. Android源码——AsynTask

    AsyncTask<Params, Progress, Result>中三个参数为: Params         输入数据 Progress       过程数据 Result     ...