H5案例分享:JS手势框架 —— Hammer.js

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演示

五、注意事项
- 试着避免垂直方向上的 pan/swipe
垂直方向上的平移操作一般是用来滚动页面的,而且有些(过时的)浏览器不会传递事件,导致Hammer无法识别这些手势。
- 在设备上做测试
有时候Hammer需要做一些调整,像swipe的速率或其它阈值,如果你在一台反应较慢的设备上做测试,那么你要保证你的回调越简单越好。
- 去掉Windows Phone点击时的高亮效果
在Windows Phone上的IE10和IE11里tap某元素时,会有一个小小的tap高亮效果,加上这个meta标签可以取消这种效果:
- 选择不了文本
Hammer设置了一个属性用来提升桌面平移操作的用户体验(UX)。常规来说,当你在桌面级浏览器上拖动页面时,你应该是可以正常选中文本的,但user-select这个CSS属性禁用了这功能。如果你在意文本选择功能,同时觉得桌面级的体验没必要太尽善尽美,你可以很轻松地取消这个默认选项——确保在创建实例之前执行:
delete Hammer.defaults.cssProps.userSelect;
5.在tap之后,导致触发了一个click事件
这种click事件我们称之为一个“幽灵点击”事件,可创建了一个小函数来避免触摸后导致click。
六、浏览器/终端的支持
Harmmer可以运行在除了IE8及其以下的任何浏览器。浏览器若对触摸行为(touch-action)提供原生支持,那么对比那些不支持HarmmerJS某些事件的浏览器,将会有更好的体验。

H5案例分享:JS手势框架 —— Hammer.js的更多相关文章
- 移动端手势库Hammer.js学习
感觉移动端原生支持的 touch.tap.swipe 几个事件好像还不够用,某些时候还会用到诸如缩放.长按等其他功能. 近日学习了一个手势库 Hammer.js,它是一个轻量级的触屏设备手势库,能识别 ...
- H5案例分享:使用JS判断客户端、浏览器、操作系统类型
使用JS判断客户端.浏览器.操作系统类型 一.JS判断客户端类型 JS判断客户端是否是iOS或者Android手机移动端 通过判断浏览器的userAgent,用正则来判断手机是否是ios和Androi ...
- 移动端手势事件 hammer.JS插件
一.引入hammer.JS 1.下载地址:http://download.csdn.net/detail/webxiaoma/9872249 2.官网地址:http ...
- 强大的 Node.js Web 框架 - Daze.js
去年年初对 Node.js 比较感兴趣,也用了很多 Node.js 的框架,但是开发体验不是特别好,我之前也是后端转前端,然后再接触 Node.js ,所以用过挺多的服务端框架,相对js而言,设计一款 ...
- H5案例分享:移动端touch事件判断滑屏手势的方向
移动端touch事件判断滑屏手势的方向 方法一 当开始一个touchstart事件的时候,获取此刻手指的横坐标startX和纵坐标startY: 当触发touchmove事件时,在获取此时手指的横坐标 ...
- H5案例分享:移动端滑屏 touch事件
移动端滑屏 touch事件 移动端触屏滑动的效果的效果在电子设备上已经被应用的越来越广泛,类似于PC端的图片轮播,但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch ...
- H5案例分享:html5移动开发细微之美
html5移动开发细微之美 1.H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 <meta name="viewport" content="width=dev ...
- H5案例分享:html5重力感应事件
html5重力感应事件 一.手机重力感应图形分析 1.设备围绕z轴的旋转角度为α,α角度的取值范围在[0,360). 设备在初始位置,与地球(XYZ)和身体(XYZ)某个位置对齐. 设备围绕z轴的旋转 ...
- Hammer.js移动端触屏框架的使用
hammer.js是一个多点触摸手势库,能够为网页加入Tap.Double Tap.Swipe.Hold.Pinch.Drag等多点触摸事件,免去自己监听底层touchstart.touchmove. ...
随机推荐
- BenUtils组件和DbUtils组件
BenUtils组件和DbUtils组件 [TOC] 1.BenUtils组件 1.1.简介 程序中对javabean的操作很频繁,所有Apache提供了一套开源api,方便javabean的操作!即 ...
- [LeetCode] Minimum Moves to Equal Array Elements 最少移动次数使数组元素相等
Given a non-empty integer array of size n, find the minimum number of moves required to make all arr ...
- [LeetCode] Rearrange String k Distance Apart 按距离为k隔离重排字符串
Given a non-empty string str and an integer k, rearrange the string such that the same characters ar ...
- Node中的定时器详解
在大多数的业务中,我们都会有一些需求,例如几秒钟实现网页的跳转,几分钟对于后台数据进行清理,node与javascript都具有将代码延迟一段时间的能力.在node中可以使用三种方式实现定时功能:超时 ...
- 内核控制Meta标签:让360浏览器默认使用极速模式打开网页(转)
为了让网站页面不那么臃肿,也懒的理IE了,同时兼顾更多的国内双核浏览器,在网页页头中添加了下面两行Meta控制标签. 1,网页头部加入 <meta name="renderer&quo ...
- mysql 基本操作
创建数据库 create database studentdb charset utf8; #创建数据库 create database studentdb charset utf8; #查看数据库的 ...
- centeros:生产环境搭建
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Helvetica Neue"; color: #e4af0a } p. ...
- java 的public private protected作用域
- winform总结3> 有趣的bat/winform程序完成自己的任务,然后把自己删除
在winform的开发过程中往往会有这样的应用场景,执行完成某任务之后,程序需要把本身删除掉.比如卸载.分享一个比较简单实现. 思路就是利用批处理,关闭文件后执行bat,bat执行删除主文件,然后删除 ...
- UICollectionViewCell 网格显示数据
using System; using System.Collections.Generic; using Foundation; using UIKit; namespace ddd { publi ...