/**
* 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. CMS(Concurrent Mark-Sweep)垃圾回收器

    http://www.iteye.com/topic/1119491 1.总体介绍: CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器.对于要 ...

  2. web 端 gantt组件选型

    gantt - 甘特图 甘特图(Gantt chart)又称为横道图.条状图(Bar chart).其通过条状图来显示项目,进度,和其他时间相关的系统进展的内在关系随着时间进展的情况.以提出者亨利·L ...

  3. Download Percona Monitoring Plugins

    https://www.percona.com/downloads/percona-monitoring-plugins/LATEST/

  4. 五、oracle 表管理

    一.表名和列名的命名规则1).必须以字母开头2).长度不能超过30个字符3).不能使用oracle的保留字4).只能使用如下字符 a-z,a-z,0-9,$,#等 二.数据类型1).字符类char 长 ...

  5. 三 Python解释器

    当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件.要运行代码,就需要Python解释器去执行.py文件. 由于整个Python语言从规范到解释器都是开源的 ...

  6. Maven下载安装步骤

    Maven下载安装步骤 1.下载maven 进入Maven官网的下载页面:http://maven.apache.org/download.cgi,如下图所示: 选择当前最新版本:"apac ...

  7. 基于Redis实现——分布式锁与实现

    实现 使用的是jedis来连接Redis. 实现思想 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通 ...

  8. 429.N叉树的层次遍历

    给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明: 树的深度不会超过 100 ...

  9. Linux 下安装gmpy2

    GMP(GNU Multiple Precision Arithmetic Library,即GNU高精度算术运算库),它是一个开源的高精度运算库,其中不但有普通的整数.实数.浮点数的高精度运算,还有 ...

  10. python的进阶--爬虫小试

    代理之说 [ python实现代理服务功能实例 ]  --  https://www.jb51.net/article/43266.htm [检测代理是否有效] -- https://blog.csd ...