/** * @author 剧中人 * @github https://github.com/bh-lay/toucher * @modified 2016-5-25 23:27 * */ (function(global,doc,factoryfn){ //初始化toucher主方法 var factory = factoryfn(global,doc); //提供window.util.toucher()接口 global.util = global.util || {}; global.util.toucher = global.util.toucher || factory; //提供commonjs规范的接口 global.define && define(function(require,exports,module){ return factory; }); })(this,document,function(window,document){ /** * class 操作 */ var supports_classlist = !!document.createelement('div').classlist, // 是否含有某个 class hasclass = supports_classlist ? function( node, classsingle ){ return node && node.classlist && node.classlist.contains( classsingle ); } : function ( node, classsingle ){ if( !node || typeof( node.classname ) !== 'string' ){ return false; } return !! node.classname.match(new regexp('(\\s|^)' + classsingle + '(\\s|$)')); }; var supporttouch = "ontouchend" in document ? true : false; /** * @method 事件触发器 * @description 根据事件最原始被触发的target,逐级向上追溯事件绑定 * * @param string 事件名 * @param object 原生事件对象 */ function emit(eventname,e){ this._events = this._events || {}; //事件堆无该事件,结束触发 if(!this._events[eventname]){ return; } //记录尚未被执行掉的事件绑定 var rest_events = this._events[eventname]; //从事件源:target开始向上冒泡 var target = e.target; while (1) { //若没有需要执行的事件,结束冒泡 if(rest_events.length ==0){ return; } //若已经冒泡至顶,检测顶级绑定,结束冒泡 if(target == this.dom || !target){ //遍历剩余所有事件绑定 for(var i=0,total=rest_events.length;i= math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'left' : 'right') : (y1 - y2 > 0 ? 'up' : 'down'); } /** * 监听原生的事件,主动触发模拟事件 * */ function eventlistener(dom){ var this_touch = this; //轻击开始时间 var touchstarttime = 0; //记录上一次点击时间 var lasttouchtime = 0; //记录初始轻击的位置 var x1,y1,x2,y2; //轻击事件的延时器 var touchdelay; //测试长按事件的延时器 var longtap; //记录当前事件是否已为等待结束的状态 var isactive = false; //记录有坐标信息的事件 var eventmark = null; //单次用户操作结束 function actionover(e){ isactive = false; cleartimeout(longtap); cleartimeout(touchdelay); } //断定此次事件为轻击事件 function issingletap(){ actionover(); emit.call(this_touch,'singletap',eventmark); } //触屏开始 function touchstart(e){ //缓存事件 eventmark = e; x1 = e.touches[0].pagex; y1 = e.touches[0].pagey; x2 = 0; y2 = 0; isactive = true; touchstarttime = new date(); emit.call(this_touch,'swipestart',e); //检测是否为长按 cleartimeout(longtap); longtap = settimeout(function(){ actionover(e); //断定此次事件为长按事件 emit.call(this_touch,'longtap',e); },500); } //触屏结束 function touchend(e){ //touchend中,拿不到坐标位置信息,故使用全局保存下数据 e.plugstartposition = eventmark.plugstartposition; e.plugtouches = eventmark.touches; emit.call(this_touch,'swipeend',e); if(!isactive){ return; } var now = new date(); //若未监听doubletap,直接响应 if(!this_touch._events.doubletap || this_touch._events.doubletap.length == 0){ issingletap(); }else if(now - lasttouchtime > 200){ //延迟响应 touchdelay = settimeout(issingletap,190); }else{ cleartimeout(touchdelay); actionover(e); //断定此次事件为连续两次轻击事件 emit.call(this_touch,'doubletap',eventmark); } lasttouchtime = now; } //手指移动 function touchmove(e){ //缓存事件 eventmark = e; //在原生事件基础上记录初始位置(为swipe事件增加参数传递) e.plugstartposition = { pagex : x1, pagey : y1 }; //断定此次事件为移动事件 emit.call(this_touch,'swipe',e); if(!isactive){ return; } x2 = e.touches[0].pagex; y2 = e.touches[0].pagey; if(math.abs(x1-x2)>2 || math.abs(y1-y2)>2){ //断定此次事件为移动手势 var direction = swipedirection(x1, x2, y1, y2); emit.call(this_touch,'swipe' + direction,e); }else{ //断定此次事件为轻击事件 issingletap(); } actionover(e); } if (supporttouch) { dom.addeventlistener('touchstart',touchstart); dom.addeventlistener('touchend',touchend); dom.addeventlistener('touchmove',touchmove); dom.addeventlistener('touchcancel',actionover); } else { dom.addeventlistener('mspointerdown',touchstart); dom.addeventlistener('pointerdown',touchstart); dom.addeventlistener('mspointerup',touchend); dom.addeventlistener('pointerup',touchend); dom.addeventlistener('mspointermove',touchmove); dom.addeventlistener('pointermove',touchmove); dom.addeventlistener('mspointercancel',actionover); dom.addeventlistener('pointercancel',actionover); } } /** * touch类 * */ function touch(dom,param){ var param = param || {}; this.dom = dom; //存储监听事件的回调 this._events = {}; //监听dom原生事件 eventlistener.call(this,this.dom); } /** * @method 增加事件监听 * @description 支持链式调用 * * @param string 事件名 * @param [string] 事件委托至某个class(可选) * @param function 符合条件的事件被触发时需要执行的回调函数 * **/ touch.prototype.on = function on(eventstr,a,b){ var classname,fn; if(typeof(a) == 'string'){ classname = a.replace(/^\./,''); fn = b; }else{ classname = null; fn = a; } //检测callback是否合法,事件名参数是否存在· if(typeof(fn) == 'function' && eventstr && eventstr.length){ var eventnames = eventstr.split(/\s+/); for(var i=0,total=eventnames.length;i