手势识别与事件库 Touch.js若干问题及解决方法

Touch.js是移动设备上的手势识别与事件库, 由百度云Clouda团队维护,也是在百度内部广泛使用的开发工具.

Touch.js的代码已托管于github并开源,希望能帮助国内更多的开发者学习和开发出优秀的App产品.

Touch.js手势库专为移动设备设计, 请在Webkit内核浏览器中使用.

极速CDN

<script src="http://code.baidu.com/touch-0.2.14.min.js"></script>

Examples

//swipe example
touch.on(‘.target‘, ‘swipeleft swiperight‘, function(ev){
    console.log("you have done", ev.type);
});

向左及向右 滑动更灵活的解决方案

参考牛人博客的代码,据说相当好用。

  1(function(global,doc,factoryFn){
  2     //初始化toucher主方法
  3     var factory = factoryFn(global,doc);
  4
  5     //提供window.util.toucher()接口
  6     global.util = global.util || {};
  7     global.util.toucher = global.util.toucher || factory;
  8
  9     //提供CommonJS规范的接口
 10     global.define && define(function(require,exports,module){
 11         //对外接口
 12         return factory;
 13     });
 14 })(this,document,function(window,document){
 15     /**
 16      * 判断是否拥有某个class
 17      */
 18     function hasClass(dom,classSingle){
 19         return dom.className.match(new RegExp(‘(\\s|^)‘ + classSingle +‘(\\s|$)‘));
 20     }
 21
 22     /**
 23      * @method 向句柄所在对象增加事件监听
 24      * @description 支持链式调用
 25      *
 26      * @param string 事件名
 27      * @param [string] 事件委托至某个class(可选)
 28      * @param function 符合条件的事件被触发时需要执行的回调函数
 29      *
 30      */
 31     function ON(eventStr,a,b){
 32         this._events = this._events || {};
 33         var className,fn;
 34         if(typeof(a) == ‘string‘){
 35             className = a.replace(/^\./,‘‘);
 36             fn = b;
 37         }else{
 38             className = null;
 39             fn = a;
 40         }
 41         //检测callback是否合法,事件名参数是否存在·
 42         if(typeof(fn) == ‘function‘ && eventStr && eventStr.length){
 43             var eventNames = eventStr.split(/\s+/);
 44             for(var i=0,total=eventNames.length;i<total;i++){
 45
 46                 var eventName = eventNames[i];
 47                 //事件堆无该事件,创建一个事件堆
 48                 if(!this._events[eventName]){
 49                     this._events[eventName] = [];
 50                 }
 51                 this._events[eventName].push({
 52                     ‘className‘ : className,
 53                     ‘fn‘ : fn
 54                 });
 55             }
 56         }
 57
 58         //提供链式调用的支持
 59         return this;
 60     }
 61
 62     /**
 63      * @method 事件触发器
 64      * @description 根据事件最原始被触发的target,逐级向上追溯事件绑定
 65      *
 66      * @param string 事件名
 67      * @param object 原生事件对象
 68      */
 69     function EMIT(eventName,e){
 70         this._events = this._events || {};
 71         //事件堆无该事件,结束触发
 72         if(!this._events[eventName]){
 73             return
 74         }
 75         //记录尚未被执行掉的事件绑定
 76         var rest_events = this._events[eventName];
 77
 78         //从事件源:target开始向上冒泡
 79         var target = e.target;
 80         while (1) {
 81             //若没有需要执行的事件,结束冒泡
 82             if(rest_events.length ==0){
 83                 return;
 84             }
 85             //若已经冒泡至顶,检测顶级绑定,结束冒泡
 86             if(target == this.dom || !target){
 87                 //遍历剩余所有事件绑定
 88                 for(var i=0,total=rest_events.length;i<total;i++){
 89                     var classStr = rest_events[i][‘className‘];
 90                     var callback = rest_events[i][‘fn‘];
 91                     //未指定事件委托,直接执行
 92                     if(classStr == null){
 93                         event_callback(eventName,callback,target,e);
 94                     }
 95                 }
 96                 return;
 97             }
 98
 99             //当前需要校验的事件集
100             var eventsList = rest_events;
101             //置空尚未执行掉的事件集
102             rest_events = [];
103
104             //遍历事件所有绑定
105             for(var i=0,total=eventsList.length;i<total;i++){
106                 var classStr = eventsList[i][‘className‘];
107                 var callback = eventsList[i][‘fn‘];
108                 //符合事件委托,执行
109                 if(hasClass(target,classStr)){
110                     //返回false停止事件冒泡及后续事件,其余继续执行
111                     if(event_callback(eventName,callback,target,e) == false){
112                         return
113                     }
114                 }else{
115                     //不符合执行条件,压回到尚未执行掉的列表中
116                     rest_events.push(eventsList[i]);
117                 }
118             }
119             //向上冒泡
120             target = target.parentNode;
121         }
122     }
123
124     /**
125      * 执行绑定的回调函数,并创建一个事件对象
126      * @param[string]事件名
127      * @param[function]被执行掉的函数
128      * @param[object]指向的dom
129      * @param[object]原生event对象
130      */
131     function event_callback(name,fn,dom,e){
132         var touch = e.touches.length ? e.touches[0] : {};
133
134         var newE = {
135             ‘type‘ : name,
136             ‘target‘ : e.target,
137             ‘pageX‘ : touch.clientX || 0,
138             ‘pageY‘ : touch.clientY || 0
139         };
140         //为swipe事件增加交互初始位置及移动距离
141         if(name == ‘swipe‘ && e.startPosition){
142             newE.startX = e.startPosition[‘pageX‘],
143             newE.startY = e.startPosition[‘pageY‘],
144             newE.moveX = newE.pageX - newE.startX,
145             newE.moveY = newE.pageY - newE.startY
146         }
147         var call_result = fn.call(dom,newE);
148         //若绑定方法返回false,阻止浏览器默认事件
149         if(call_result == false){
150             e.preventDefault();
151             e.stopPropagation();
152         }
153
154         return call_result;
155     }
156     /**
157      * 判断swipe方向
158      */
159     function swipeDirection(x1, x2, y1, y2) {
160         return Math.abs(x1 - x2) >=
161             Math.abs(y1 - y2) ? (x1 - x2 > 0 ? ‘Left‘ : ‘Right‘) : (y1 - y2 > 0 ? ‘Up‘ : ‘Down‘)
162     }
163
164     /**
165      * 监听原生的事件,主动触发模拟事件
166      *
167      */
168     function eventListener(DOM){
169         var this_touch = this;
170
171         //轻击开始时间
172         var touchStartTime = 0;
173
174         //记录上一次点击时间
175         var lastTouchTime = 0;
176
177         //记录初始轻击的位置
178         var x1,y1,x2,y2;
179
180         //轻击事件的延时器
181         var touchDelay;
182
183         //测试长按事件的延时器
184         var longTap;
185
186         //记录当前事件是否已为等待结束的状态
187         var isActive = false;
188         //记录有坐标信息的事件
189         var eventMark = null;
190         //单次用户操作结束
191         function actionOver(e){
192             isActive = false;
193             clearTimeout(longTap);
194             clearTimeout(touchDelay);
195         }
196
197         //触屏开始
198         function touchStart(e){
199             //缓存事件
200             eventMark = e;
201
202             x1 = e.touches[0].pageX;
203             y1 = e.touches[0].pageY;
204             x2 = 0;
205             y2 = 0;
206             isActive = true;
207             touchStartTime = new Date();
208             EMIT.call(this_touch,‘swipeStart‘,e);
209             //检测是否为长按
210             clearTimeout(longTap);
211             longTap = setTimeout(function(){
212                 actionOver(e);
213                 //断定此次事件为长按事件
214                 EMIT.call(this_touch,‘longTap‘,e);
215             },500);
216         }
217         //触屏结束
218         function touchend(e){
219             //touchend中,拿不到坐标位置信息,故使用全局保存下的事件
220             EMIT.call(this_touch,‘swipeEnd‘,eventMark);
221             if(!isActive){
222                 return
223             }
224             var now = new Date();
225             if(now - lastTouchTime > 260){
226                 touchDelay = setTimeout(function(){
227                     //断定此次事件为轻击事件
228                     actionOver();
229                     EMIT.call(this_touch,‘singleTap‘,eventMark);
230                 },250);
231             }else{
232                 clearTimeout(touchDelay);
233                 actionOver(e);
234                 //断定此次事件为连续两次轻击事件
235                 EMIT.call(this_touch,‘doubleTap‘,eventMark);
236             }
237             lastTouchTime = now;
238         }
239
240         //手指移动
241         function touchmove(e){
242             //缓存事件
243             eventMark = e;
244             //在原生事件基础上记录初始位置(为swipe事件增加参数传递)
245             e.startPosition = {
246                 ‘pageX‘ : x1,
247                 ‘pageY‘ : y1
248             };
249             //断定此次事件为移动事件
250             EMIT.call(this_touch,‘swipe‘,e);
251
252             if(!isActive){
253                 return
254             }
255            x2 = e.touches[0].pageX
256             y2 = e.touches[0].pageY
257             if(Math.abs(x1-x2)>2 || Math.abs(y1-y2)>2){
258                 //断定此次事件为移动手势
259                 var direction = swipeDirection(x1, x2, y1, y2);
260                 EMIT.call(this_touch,‘swipe‘ + direction,e);
261             }else{
262                 //断定此次事件为轻击事件
263                 actionOver(e);
264                 EMIT.call(this_touch,‘singleTap‘,e);
265             }
266             actionOver(e);
267         }
268
269         /**
270          * 对开始手势的监听
271          */
272         DOM.addEventListener(‘touchstart‘,touchStart);
273         DOM.addEventListener(‘MSPointerDown‘,touchStart);
274         DOM.addEventListener(‘pointerdown‘,touchStart);
275
276         /**
277          * 对手势结束的监听(轻击)
278          */
279         DOM.addEventListener(‘touchend‘,touchend);
280         DOM.addEventListener(‘MSPointerUp‘,touchend);
281         DOM.addEventListener(‘pointerup‘,touchend);
282
283         /**
284          * 对移动手势的监听
285          */
286         DOM.addEventListener(‘touchmove‘,touchmove);
287         DOM.addEventListener(‘MSPointerMove‘,touchmove);
288         DOM.addEventListener(‘pointermove‘,touchmove);
289
290         /**
291          * 对移动结束的监听
292          */
293         DOM.addEventListener(‘touchcancel‘,actionOver);
294         DOM.addEventListener(‘MSPointerCancel‘,actionOver);
295         DOM.addEventListener(‘pointercancel‘,actionOver);
296     }
297
298     /**
299      * touch类
300      *
301      */
302     function touch(DOM,param){
303         var param = param || {};
304
305         this.dom = DOM;
306         //监听DOM原生事件
307         eventListener.call(this,this.dom);
308     }
309     //拓展事件绑定方法
310     touch.prototype[‘on‘] = ON;
311
312     //对外提供接口
313     return function (dom){
314         return new touch(dom);
315     };
316 });

解决除谷歌浏览器之外的浏览器兼容性方案

1:jquery mobile里面的touch组件。

1:百度的童鞋们实现的touch.js.网址也贴一下吧: http://touch.code.baidu.com/

3:参考大神的:

(function($) {
  var options, Events, Touch;
  options = {
    x: 20,
    y: 20
  };
  Events = [‘swipe‘, ‘swipeLeft‘, ‘swipeRight‘, ‘swipeUp‘, ‘swipeDown‘, ‘tap‘, ‘longTap‘, ‘drag‘];
  Events.forEach(function(eventName) {
    $.fn[eventName] = function() {
      var touch = new Touch($(this), eventName);
      touch.start();
      if (arguments[1]) {
        options = arguments[1]
      }
      return this.on(eventName, arguments[0])
    }
  });
  Touch = function() {
    var status, ts, tm, te;
    this.target = arguments[0];
    this.e = arguments[1]
  };
  Touch.prototype.framework = function(e) {
    e.preventDefault();
    var events;
    if (e.changedTouches) events = e.changedTouches[0];
    else events = e.originalEvent.touches[0];
    return events
  };
  Touch.prototype.start = function() {
    var self = this;
    self.target.on("touchstart",
    function(event) {
      event.preventDefault();
      var temp = self.framework(event);
      var d = new Date();
      self.ts = {
        x: temp.pageX,
        y: temp.pageY,
        d: d.getTime()
      }
    });
    self.target.on("touchmove",
    function(event) {
      event.preventDefault();
      var temp = self.framework(event);
      var d = new Date();
      self.tm = {
        x: temp.pageX,
        y: temp.pageY
      };
      if (self.e == "drag") {
        self.target.trigger(self.e, self.tm);
        return
      }
    });
    self.target.on("touchend",
    function(event) {
      event.preventDefault();
      var d = new Date();
      if (!self.tm) {
        self.tm = self.ts
      }
      self.te = {
        x: self.tm.x - self.ts.x,
        y: self.tm.y - self.ts.y,
        d: (d - self.ts.d)
      };
      self.tm = undefined;
      self.factory()
    })
  };
  Touch.prototype.factory = function() {
    var x = Math.abs(this.te.x);
    var y = Math.abs(this.te.y);
    var t = this.te.d;
    var s = this.status;
    if (x < 5 && y < 5) {
      if (t < 300) {
        s = "tap"
      } else {
        s = "longTap"
      }
    } else if (x < options.x && y > options.y) {
      if (t < 250) {
        if (this.te.y > 0) {
          s = "swipeDown"
        } else {
          s = "swipeUp"
        }
      } else {
        s = "swipe"
      }
    } else if (y < options.y && x > options.x) {
      if (t < 250) {
        if (this.te.x > 0) {
          s = "swipeLeft"
        } else {
          s = "swipeRight"
        }
      } else {
        s = "swipe"
      }
    }
    if (s == this.e) {
      this.target.trigger(this.e);
      return
    }
  }
})(window.jQuery || window.Zepto);
时间: 2024-08-25 19:10:14

手势识别与事件库 Touch.js若干问题及解决方法的相关文章

touch.js - 移动设备上的手势识别与事件库

Touch.js 是移动设备上的手势识别与事件库, 由百度云Clouda团队维护,也是在百度内部广泛使用的开发工具.Touch.js手势库专为移动设备设计.Touch.js对于网页设计师来说,是一款不错的辅助工具,可以减少很多写框架控制器的时间.网页合理使用Touch.js不但能增加网页的美观感,而且在节约时间,减少人力投入也有极大的帮助. Touch.js官网: https://www.awesomes.cn/repo/Clouda-team/touchjsgithub:https://git

.NET获取不到js写的cookie解决方法

今晚使用javascript设置一个来路的cookie,之后使用ASP.NET获取这个cookie值,发现ASP.NET获取不到JS设置的cookie值,真郁闷中,以下是JS写Cookie的代码: Code //写cookies functionsetCookie(name,value) { document.cookie=name"="escape(value)";";//设置的cookie关闭浏览即失效 } //JS设置来路写入到cookie setCookie

javascript使用for循环批量注册的事件不能正确获取索引值的解决方法

今天遇到一个问题,那就是当使用for循环批量注册事件处理函数,然后最后通过事件处理函数获取当前元素的索引值的时候会失败,先看一段代码实例: <script type="text/javascript"> window.onload=function(){ var oLis=document.getElementsByTagName("li"); var oshow=document.getElementById("show"); fo

PHP使用GD2库画图,图像无法输出解决方法

在CS6编辑环境下,使用php的GD2库绘制图像,在浏览器上输出可能会出现图像无法输出的情况,目前发现两个解决方法:方法1:用记事本写,再另存为utf-8 no bom的格式. 方法2:在代码中添加ob_clean()函数,清空(擦掉)输出缓冲区. 代码如下: <?php //用其他编辑器打开存储为utf-8 no bom ob_clean();/* 清空(擦掉)输出缓冲区,不加此行可能无法显示图像*/ $height=600; $width=600; //创建一个图像标识符 $im=image

JS 一些问题与解决方法

一.post/get传输json数据中包含特殊字符 二.<form>表单submit后不提交的解决方法 三.JS获取<form>表单中<input type='file'>,并提交给服务器的解决方法

JS事件监听 JS:attachEvent和addEventListener 使用方法

attachEvent与addEventListener区别 适应的浏览器版本不同,同时在使用的过程中要注意attachEvent方法          按钮onclickaddEventListener方法    按钮click 两者使用的原理:可对执行的优先级不一样的事件进行操作:attachEvent方法,为某一事件附加其它的处理事件.(不支持Mozilla系列) addEventListener方法 用于 Mozilla系列 举例: Js代码 document.getElementByI

js跨域及解决方法

什么是跨域 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦.这里把涉及到跨域的一些问题简单地整理一下: 首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象.更详细的说明可以看下表: URL 说明 是否允许通信 http://www.a.com/a.js http://www.a.com/b.js 同一域名下 允许

ajax.googleapis.com等公共库加载被“墙”的解决方法!

今天打算在stackoverflow上注册账号提些问题:结果不管怎么样都无法sign up上去,点击按钮没有反应,最后通过打开chrome调试发现stackoverflow有访问到"ajax.googleapis.com"的jquery.js资源,由于google已经完全被墙了,所以这个页面也就无法正常的执行JS脚本. 在网上查找到一个解决方案,不用翻墙,通过chrome的插件拦截地址将地址替换成国内的CDN库:感觉还是挺方便的: chrome插件对应的源代码地址:https://gi

Js文件红叉解决方法

1.  右键js文件 2.  选择[MyEclipse] 3.  点击[ExculdeFrom Validation]