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. ...
随机推荐
- Duplicate entry 'javajavajav' for key 'username'
org.apache.ibatis.exceptions.PersistenceException: ### Error updating database. Cause: com.mysql.jd ...
- 继承AppCompatActivity的Activity隐藏标题栏
继承了AppCompatActivity的Activity无法通过调用requestWindowFeature(Window.FEATURE_NO_TITLE)来隐藏标题栏. public class ...
- Heartbeat使用梳理
在日常的集群系统架构中,一般用到Heartbeat的主要就2种:1)高可用(High Availability)HA集群, 使用Heartbeat实现,也称为"双机热备", &qu ...
- Log4j配置详解(转)
一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局).这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出.综合使 ...
- JAVA的正则表达式-学习
1.正则表达式作用 正则表达式,是用来匹配字符串的,即检查一定的格式,还能按格式进行分组,替换......其实,不用正则表达式,也可以编.但是,大多数情况下,正则表达式可以提高你编程的效率. 2.学习 ...
- python网络编程-OSI七层模型详解
OSI 七层模型通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯,因此其最主要的功能就是帮助不同类型的主机实现数据传输 . 完成中继功能的节点通常称为中继系统.在OSI七层模型中,处于 ...
- HTTP相关函数
1.headers_list() //返回头部信息 2.header("Content-type: text/html; charset=utf-8") //修改编码 3.head ...
- java使用tomcat7的maven插件发布到服务器
服务器容器使用tomcat7的maven插件,使用该插件不需要使用tomcat服务器.以下示例均以paycore项目为例. 一.使用tomcat7-maven-plugin 首先在主pom(payco ...
- vue.js第六课
class与style绑定 绑定HTML class 对象语法 数组语法 绑定内联样式 对象语法 数组语法 自动添加前缀 1.class与style绑定. 数据绑定一个常见需求就是 操作元素的clas ...
- 如何从Exchange邮箱数据库批量删除特定邮件