/**
* Toucher
* git:https://github.com/cometwo/Toucher-1
*/ "use strict"; (function (root, factory) {
if (typeof define === "function" && define.amd) {
define([], function () {
return factory(root);
});
} else {
root.Toucher = factory(root);
}
}(window, function (root, undefined) { if (!"ontouchstart" in window) {
return;
} var _wrapped; // 获取对象上的类名
function _typeOf(obj) {
return Object.prototype.toString.call(obj).toLowerCase().slice(8, -1);
} // 获取当前时间戳
function getTimeStr() {
return +(new Date());
} // 获取位置信息
function getPosInfo(ev) {
var _touches = ev.touches;
if (!_touches || _touches.length === 0) {
return;
}
return {
pageX: ev.touches[0].pageX,
pageY: ev.touches[0].pageY,
clientX: ev.touches[0].clientX || 0,
clientY: ev.touches[0].clientY || 0
};
} // 绑定事件
function bindEv(el, type, fn) {
if (el.addEventListener) {
el.addEventListener(type, fn, false);
} else {
el["on" + type] = fn;
}
} // 解绑事件
function unBindEv(el, type, fn) {
if (el.removeEventListener) {
el.removeEventListener(type, fn, false);
} else {
el["on" + type] = fn;
}
} // 获得滑动方向
function getDirection(startX, startY, endX, endY) {
var xRes = startX - endX;
var xResAbs = Math.abs(startX - endX);
var yRes = startY - endY;
var yResAbs = Math.abs(startY - endY);
var direction = ""; if (xResAbs >= yResAbs && xResAbs > 25) {
direction = (xRes > 0) ? "Right" : "Left";
} else if (yResAbs > xResAbs && yResAbs > 25) {
direction = (yRes > 0) ? "Down" : "Up";
}
return direction;
} // 取得两点之间直线距离
function getDistance(startX, startY, endX, endY) {
return Math.sqrt(Math.pow((startX - endX), 2) + Math.pow((startY - endY), 2));
} function getLength(pos) {
return Math.sqrt(Math.pow(pos.x, 2) + Math.pow(pos.y, 2));
} function cross(v1, v2) {
return v1.x * v2.y - v2.x * v1.y;
} // 取向量
function getVector(startX, startY, endX, endY) {
return (startX * endX) + (startY * endY);
} // 获取角度
function getAngle(v1, v2) {
var mr = getLength(v1) * getLength(v2);
if (mr === 0) {
return 0
}
;
var r = getVector(v1.x, v1.y, v2.x, v2.y) / mr;
if (r > 1) {
r = 1;
}
return Math.acos(r);
} // 获取旋转的角度
function getRotateAngle(v1, v2) {
var angle = getAngle(v1, v2);
if (cross(v1, v2) > 0) {
angle *= -1;
}
return angle * 180 / Math.PI;
} // 包装一个新的事件对象
function wrapEvent(ev, obj) {
var res = {
touches: ev.touches,
type: ev.type
};
if (_typeOf(obj) === "object") {
for (var i in obj) {
res[i] = obj[i];
}
}
return res;
} // 把伪数组转换成数组
function toArray(list) {
if (list && (typeof list === "object") && isFinite(list.length) && (list.length >= 0) && (list.length === Math.floor(list.length)) && list.length < 4294967296) {
return [].slice.call(list);
}
} // 判断一个元素列表里面是否有多个元素
function isContain(collection, el) {
if (arguments.length === 2) {
return collection.some(function (elItem) {
return el.isEqualNode(elItem);
});
}
return false;
} // 生成一个随机id
function uId() {
return Math.random().toString(16).slice(2);
} // 事件模块
var Event = (function () { var storeEvents = {}; return { // add an event handle
add: function (type, el, handler) {
var selector = el,
len = arguments.length,
finalObject = {}, _type;
/**
* Event.add("swipe", function() {
* // ...
* });
*/ if (_typeOf(el) === "string") {
el = document.querySelectorAll(el);
} if (len === 2 && _typeOf(el) === "function") {
finalObject = {
handler: el
};
} else if (len === 3 && el instanceof HTMLElement || el instanceof NodeList && _typeOf(handler) === "function") {
/**
* Event.add("swipe", "#div", function(ev) {
* // ...
* });
*/
_type = _typeOf(el);
finalObject = {
type: _type,
selector: selector,
el: _type === "nodelist" ? toArray(el) : el,
handler: handler
};
} if (!storeEvents[type]) {
storeEvents[type] = [];
} storeEvents[type].push(finalObject);
}, // remove an event handle
remove: function (type, selector) {
var len = arguments.length;
if (_typeOf(type) === "string" && _typeOf(storeEvents[type]) === "array" && storeEvents[type].length) {
if (len === 1) {
storeEvents[type] = [];
} else if (len === 2) {
storeEvents[type] = storeEvents[type].filter(function (item) {
return !(item.selector === selector || _typeOf(selector) !== "string" && item.selector.isEqualNode(selector));
});
}
}
}, // trigger an event handle
trigger: function (type, el, argument) {
var len = arguments.length; /**
* Event.trigger("swipe", document.querySelector("#div"), {
* // ...
* });
*/
if (len === 3 && _typeOf(storeEvents[type]) === "array" && storeEvents[type].length) {
storeEvents[type].forEach(function (item) {
if (_typeOf(item.handler) === "function") {
if (item.type && item.el) {
argument.target = el;
if (item.type === "nodelist" && isContain(item.el, el)) {
item.handler(argument);
} else if (item.el.isEqualNode && item.el.isEqualNode(el)) {
item.handler(argument);
}
} else {
item.handler(argument);
}
}
});
}
}
};
})(); // 构造函数
function Toucher(selector) {
return new Toucher.fn.init(selector);
} Toucher.fn = Toucher.prototype = { // 修改原型构造器
constructor: Toucher, // 初始化方法
init: function (selector) {
this.el = selector instanceof HTMLElement ? selector :
_typeOf(selector) === "string" ? document.querySelector(selector) : null;
if (_typeOf(this.el) === "null") {
throw new Error("you must specify a particular selector or a particular DOM object");
}
this.scale = 1;
this.pinchStartLen = null;
this.isDoubleTap = false;
this.triggedSwipeStart = false;
this.triggedLongTap = false;
this.delta = null;
this.last = null;
this.now = null;
this.tapTimeout = null;
this.singleTapTimeout = null;
this.longTapTimeout = null;
this.swipeTimeout = null;
this.startPos = {};
this.endPos = {};
this.preTapPosition = {}; this.cfg = {
doubleTapTime: 400,
longTapTime: 700
}; // 绑定4个事件
bindEv(this.el, "touchstart", this._start.bind(this));
bindEv(this.el, "touchmove", this._move.bind(this));
bindEv(this.el, "touchcancel", this._cancel.bind(this));
bindEv(this.el, "touchend", this._end.bind(this));
return this;
}, // 提供config方法进行配置
config: function (option) {
if (_typeOf(option) !== "object") {
throw new Error("method Toucher.config must pass in an anguments which is an instance of Object, but passed in " + option.toString());
}
for (var i in option) {
this.cfg[i] = option[i];
}
return this;
}, // on方法绑定事件
/**
* var toucher = Toucher({...});
*
* toucher.on("swipe", function(ev) {
* // ...
* });
*
* // or
*
* toucher.on("tap", "#id", function(ev) {
* // ...
* });
*
* support events: singleTap,longTap,swipe,swipeStart,swipeEnd,swipeUp,swipeRight,swipeDown,swipeLeft,pinch,rotate
*
*/ on: function (type, el, callback) {
var len = arguments.length;
if(len === 2) {
Event.add(type, el);
} else {
Event.add(type, el, callback);
}
return this;
}, // off 解除绑定
/**
* var toucher = Toucher({...});
* toucher.off(type);
*
* // or
*
* toucher.off(type, selector);
*/
off: function (type, selector) {
Event.remove(type, selector);
return this;
}, // 手指刚触碰到屏幕
_start: function (ev) {
if (!ev.touches || ev.touches.length === 0) {
return;
} var self = this;
var otherToucher, v,
preV = this.preV,
target = ev.target; self.now = getTimeStr();
self.startPos = getPosInfo(ev);
self.delta = self.now - (self.last || self.now);
self.triggedSwipeStart = false;
self.triggedLongTap = false; // 快速双击
if (JSON.stringify(self.preTapPosition).length > 2 && self.delta < self.cfg.doubleTapTime && getDistance(self.preTapPosition.clientX, self.preTapPosition.clientY, self.startPos.clientX, self.startPos.clientY) < 25) {
self.isDoubleTap = true;
} // 长按定时
self.longTapTimeout = setTimeout(function () {
_wrapped = {
el: self.el,
type: "longTap",
timeStr: getTimeStr(),
position: self.startPos
};
Event.trigger("longTap", target, _wrapped);
self.triggedLongTap = true;
}, self.cfg.longTapTime); // 多个手指放到屏幕
if (ev.touches.length > 1) {
self._cancelLongTap();
otherToucher = ev.touches[1];
v = {
x: otherToucher.pageX - self.startPos.pageX,
y: otherToucher.pageY - self.startPos.pageY
};
this.preV = v;
self.pinchStartLen = getLength(v);
self.isDoubleTap = false;
} self.last = self.now;
self.preTapPosition = self.startPos; ev.preventDefault();
}, // 手指在屏幕上移动
_move: function (ev) {
if (!ev.touches || ev.touches.length === 0) {
return;
} var v, otherToucher;
var self = this;
var len = ev.touches.length;
var posNow = getPosInfo(ev);
var preV = self.preV;
var currentX = posNow.pageX;
var currentY = posNow.pageY;
var target = ev.target; // 手指移动取消长按事件和双击
self._cancelLongTap();
self.isDoubleTap = false; // 一次按下抬起只触发一次swipeStart
if (!self.triggedSwipeStart) {
_wrapped = {
el: self.el,
type: "swipeStart",
timeStr: getTimeStr(),
position: posNow
};
Event.trigger("swipeStart", target, _wrapped);
self.triggedSwipeStart = true;
} else {
_wrapped = {
el: self.el,
type: "swipe",
timeStr: getTimeStr(),
position: posNow
};
Event.trigger("swipe", target, _wrapped);
} if (len > 1) {
otherToucher = ev.touches[1];
v = {
x: otherToucher.pageX - currentX,
y: otherToucher.pageY - currentY
}; // 缩放
_wrapped = wrapEvent(ev, {
el: self.el,
type: "pinch",
scale: getLength(v) / this.pinchStartLen,
timeStr: getTimeStr(),
position: posNow
});
Event.trigger("pinch", target, _wrapped); // 旋转
_wrapped = wrapEvent(ev, {
el: self.el,
type: "rotate",
angle: getRotateAngle(v, preV),
timeStr: getTimeStr(),
position: posNow
});
Event.trigger("rotate", target, _wrapped);
ev.preventDefault();
} self.endPos = posNow;
}, // 触碰取消
_cancel: function (ev) {
clearTimeout(this.longTapTimeout);
clearTimeout(this.tapTimeout);
clearTimeout(this.swipeTimeout);
clearTimeout(self.singleTapTimeout);
}, // 手指从屏幕离开
_end: function (ev) {
if (!ev.changedTouches) {
return;
} // 取消长按
this._cancelLongTap(); var self = this;
var direction = getDirection(self.endPos.clientX, self.endPos.clientY, self.startPos.clientX, self.startPos.clientY);
var callback, target = ev.target; if (direction !== "") {
self.swipeTimeout = setTimeout(function () {
_wrapped = wrapEvent(ev, {
el: self.el,
type: "swipe",
timeStr: getTimeStr(),
position: self.endPos
});
Event.trigger("swipe", target, _wrapped); // 获取具体的swipeXyz方向
callback = self["swipe" + direction];
_wrapped = wrapEvent(ev, {
el: self.el,
type: "swipe" + direction,
timeStr: getTimeStr(),
position: self.endPos
});
Event.trigger(("swipe" + direction), target, _wrapped); _wrapped = wrapEvent(ev, {
el: self.el,
type: "swipeEnd",
timeStr: getTimeStr(),
position: self.endPos
});
Event.trigger("swipeEnd", target, _wrapped);
}, 0);
} else if (!self.triggedLongTap) {
self.tapTimeout = setTimeout(function () {
if (self.isDoubleTap) {
_wrapped = wrapEvent(ev, {
el: self.el,
type: "doubleTap",
timeStr: getTimeStr(),
position: self.startPos
});
Event.trigger("doubleTap", target, _wrapped);
clearTimeout(self.singleTapTimeout);
self.isDoubleTap = false;
} else {
self.singleTapTimeout = setTimeout(function () {
_wrapped = wrapEvent(ev, {
el: self.el,
type: "singleTap",
timeStr: getTimeStr(),
position: self.startPos
});
Event.trigger("singleTap", target, _wrapped);
}, 100);
}
}, 0);
} this.startPos = {};
this.endPos = {};
}, // 取消长按定时器
_cancelLongTap: function () {
if (_typeOf(this.longTapTimeout) !== "null") {
clearTimeout(this.longTapTimeout);
}
}
}; Toucher.fn.init.prototype = Toucher.fn; return Toucher; }));

Toucher

移动端手势库

API

Toucher("#node").config(Object).on(Object)

    或者

var toucher = Toucher("#node");
toucher.config(Object);
toucher.on(name, callback);

通过

var toucher = Toucher(css selector);

来构造一个Toucher对象

toucher.config(Object)

来配置相关事件的触发条件

touch.on(name, callbck);

touch.on(name, target, callbck);

来绑定事件

完整示例

//  HTML
<div id="toucher">
<div id="event"></div>
<ul>
<li class="list-item"></li>
<li class="list-item"></li>
<li class="list-item"></li>
<li class="list-item"></li>
<li class="list-item"></li>
<li class="list-item"></li>
</ul>
</div> // javascript
var toucher = Toucher("#toucher"); // 回调函数会在任何时候被执行,只要event.target为<div>#toucher或者其子元素
toucher.on("singleTap", function(ev) {
// ...
}); // 只有当event.target为<div>#event的时候,才会执行后面的回调函数
toucher.on("singleTap", "#event", function(ev) {
// ...
}); // 只有当event.target为<li>.list-item的时候,才会执行后面的回调函数
toucher.on("singleTap", document.querySelector(".list-item"), function(ev) {
// ...
});

支持的配置项(config)和事件列表(on)

  • config
属性 含义 类型
longTapTime 触发longTap事件的时间(毫秒),默认700ms Number
doubleTapTime 在多少毫秒内连续点击两次屏幕,触发doubleTap,默认400ms Number
  • on
两个参数
name属性 含义 callback类型
singleTap 轻击(单个手指) Fucntion
doubleTap 手指放到屏幕(单个手指) Fucntion
longTap 长按 Fucntion
swipe 手指在屏幕上移动 Fucntion
swipeStart 手指在屏幕上移动(只触发一次) Fucntion
swipeEnd 下滑 Fucntion
swipeUp 左滑 Fucntion
swipeRight 右滑 Fucntion
swipeDown 下滑 Fucntion
swipeLeft 左滑 Fucntion
pinch 缩放 Fucntion
rotate 旋转 Fucntion
三个参数

name和callback和上表一样

target可以为具体的css selector, 也可以为具体的DOM元素(document.querySelector(selector)之类方法获取到的)

  • off

解除之前绑定过的代理事件(之前怎样绑定的就怎样解除)

例子
var toucher = Toucher("#div");

//  绑定
toucher.on("singleTap", function(ev){}); // 解除绑定
toucher.off("sigleTap");

或者

var toucher = Toucher("#div");

//  绑定
toucher.on("singleTap", ".list-item", function(ev){}); // 解除绑定
toucher.off("sigleTap", ".list-item");

在线体验

扫描下方二维码或者手机直接访问https://rwson.github.io/Toucher/

强悍的javascript手势库的更多相关文章

  1. 实现一个javascript手势库 -- base-gesture.js

    现在移动端这么普及呢,我们在手机上可以操作更多了.对于网页来说实现一些丰富的操作感觉也是非常有必要的,对吧(如果你仅仅需要click,,那就当我没说咯...)~~比如实现上下,左右滑动,点击之类的,加 ...

  2. Javascript触屏手势库-JTouch(更新V1.1)

    作者:痞子|时间:2013-05-21|分类目录:js,javascript,jquery教程|Tag标签: javascript.jTouch|阅读(857) 7 条评论 Javascript触屏手 ...

  3. ♫【异步】短小强悍的JavaScript异步调用库

    短小强悍的JavaScript异步调用库 var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) ...

  4. ABP(现代ASP.NET样板开发框架)系列之21、ABP展现层——Javascript函数库

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之21.ABP展现层——Javascript函数库 ABP是“ASP.NET Boilerplate Project ...

  5. 超小Web手势库AlloyFinger原理

    目前AlloyFinger作为腾讯手机QQ web手势解决方案,在各大项目中都发挥着作用. 感兴趣的同学可以去Github看看:https://github.com/AlloyTeam/AlloyFi ...

  6. Webix JavaScript UI 库可以帮你构建跨平台的HTML5 和 CSS3 程序

    XB 软件公司最近发布了JavaScript UI 库Webix ,其中包含的组件超过45个,用这些组件可以构建跟HTML5 和 CSS3 兼容的程序,这些程序不仅能在个人电脑上运行,还能用在iOS. ...

  7. 移动端手势库hammerJS 2.0.4官方文档翻译

    hammerJS是一个优秀的.轻量级的触屏设备手势库,现在已经更新到2.04版本,跟1.0版本有点天壤地别了,毕竟改写了事件名并新增了许多方法,允许同时监听多个手势.自定义识别器,也可以识别滑动方向. ...

  8. ECharts-基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表

    ECharts http://ecomfe.github.com/echarts 基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算 ...

  9. hammer.js手势库使用

    hammer.js是一款移动端手势库组件,支持pan(拖动).swipe(滑动).tap(轻触).press(按压,即长按).doubletap(双击)等很多手势操作,提供比较完善的事件监听机制,但是 ...

随机推荐

  1. u-boot中的Makefile

    在windos下,pc机上电之后,BIOS会初始化硬件配置,为内核传递参数,引导操作系统启动,并且识别C盘.D盘.等整个操作系统启动起来之后,才可以运行应用程序比如QQ.QQ音影.同理,在嵌入式Lin ...

  2. PHP扩展插件 imagick 、PDO_MYSQL 安装

    环境准备 echo $LC_ALL echo "export LC_ALL=C" >> /etc/profile source /etc/profile yum ins ...

  3. HDU 2102 A计划(BFS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 题目大意:公主被关在一个两层的迷宫里,迷宫的入口是S(0,0,0),公主的位置用P表示,时空传输 ...

  4. 冒泡法的算法最佳情况下的时间复杂度为什么是O(n)

    我在许多书本上看到冒泡排序的最佳时间复杂度是O(n),即是在序列本来就是正序的情况下. 但我一直不明白这是怎么算出来的,因此通过阅读<算法导论-第2版>的2.2节,使用对插入排序最佳时间复 ...

  5. bootstrap navbar items alignment

    https://stackoverflow.com/questions/19733447/bootstrap-navbar-with-left-center-or-right-aligned-item ...

  6. 怎么修改chrome浏览器的字体

    点击“自定义字体”可以修改字体风格.   如果习惯看微软雅黑的字体,我们可以点击“宋体”进入字体选择,拖动向下可以找到“微软雅黑”的字体,点击“微软雅黑”,然后再点击“完成”即可.   另外如果设置字 ...

  7. mac环境下使用brew安装kafka

    1.安装kafka brew install kafka note: ·kafka使用zookeeper管理,安装过程会自动安装zookeeper ·安装目录:/usr/local/Cellar/ka ...

  8. 【转】Android打印机--没有设备驱动sdk,自己实现USB打印功能

    原文:http://blog.csdn.net/johnwcheung/article/details/71576833 Android下的设备调试,如果设备提供了驱动,按照厂家的驱动调试即可:设备未 ...

  9. jquery和原生js-ajax

    form表单 $('#submit').click(function(){ $('#form').serialize(); //会根据input里面的name,把数据序列化成字符串:eg:name=y ...

  10. loadrunner 学习笔记--AJAX

    用loadrunner测试WEB程序的时候总是会碰到AJAX或者ActiveX实现的功能,而通常这些功能会包含很多客户端函数(一般为JavaScript).我们该如何处理?如果从功能实现的角度去考虑这 ...