最近在做一个手机版的项目,而做手机网页,那么就会考虑到用轻量级库,用jquery的话,会比较庞大,而我们就选用 zepto.js 来做开发,可是在开发的时候要用到手势事件(比如左右滑动,上下滑动),于是就在网上查了一下 zepto.js 的官网,发现有 touch 事件来模拟手势事件,这个开发就会带来便利,而不用去写JS底层代码;在网上搜罗了一下 zepto.js touch 库,找到了不多 touch.js 的相关信息,真的感觉很少(不知道是不是zepto.js不成熟的表现),终于在网上搜罗到了一个外国人写的 touch.js 库,然后就用在了项目上,但是在用到的时候,发现 swipeLeft ,swipeRight 这些事件会有一些 bug 而且不灵活,最后又在网上搜罗了一个国人修改的,但是最后用起来还是不咋滴(敏感度有点差),最后在群里问问大神们,发现有个高手他说他自己写了一个库,于是乎我就跟他聊了几下,然后他告诉他的代码放在了 github 上,那么我就上去抄了下来,用在了项目上,顿时感觉手势事件灵活了,不错,真心不错,还是得谢谢那个哥们,好了,说了那么多就上代码吧,把这个库压缩一下,引用在项目上就可以使用 swipeLeft,swipeRight 这些事件了,由于本人只用了向左向右的滑动事件,就没有测试向上向下滑动了,如果使用过这些事件的童鞋,也可以告诉我,让我也好知道一下 ^_^... 使用方法,请查看这位高手的博客 https://github.com/bh-lay/toucher/blob/master/touch.html
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 });
时间: 2024-10-25 12:47:44