在移动端常常须要处理滑动事件,好比banner图的左滑右滑,都须要事件响应,这在PC端是没有这类事件的。而在zepto.js中,下载下来的代码也并无自动加上对这类事件的支持,可是有提供相应的模块,须要你本身加上去(下表中最后一个touch模块):javascript
module | default | description |
---|---|---|
zepto | ✔ | 核心模块;包含许多方法 |
event | ✔ | 经过on() & off() 处理事件 |
ajax | ✔ | XMLHttpRequest 和 JSONP 实用功能 |
form | ✔ | 序列化 & 提交web表单 |
ie | ✔ | 增长支持桌面的Internet Explorer 10+和Windows Phone 8。 |
detect | 提供 $.os 和 $.browser 消息 |
|
fx | The animate() 方法 |
|
fx_methods | 以动画形式的 show , hide , toggle , 和 fade*() 方法. |
|
assets | 实验性支持从DOM中移除image元素后清理iOS的内存。 | |
data | 一个全面的 data() 方法, 可以在内存中存储任意对象。 |
|
deferred | 提供 $.Deferred promises API. 依赖"callbacks" 模块. 当包含这个模块时候, $.ajax() 支持promise接口链式的回调。 |
|
callbacks | 为"deferred"模块提供 $.Callbacks 。 |
|
selector | 实验性的支持 jQuery CSS 表达式 实用功能,好比 $('div:first') 和el.is(':visible') 。 |
|
touch | 在触摸设备上触发tap– 和 swipe– 相关事件。这适用于全部的`touch`(iOS, Android)和`pointer`事件(Windows Phone)。 |
这些模块的代码能够直接加在zepto.js的最底部,像拼积木同样,选择模块而后加上去拼合一份适合本身项目的增强版zepto.js。css
关于代码中是如何实现的事件这里不作过多解读,核心确定是经过touch坐标的差值判断究竟是左滑仍是上滑。这里主要讲的是touch模块中的一个坑,那就是会和国内的主流手机浏览器的默认事件冲突。具体表现就是,给一个元素绑定左滑动后,在UC浏览器中滑动该元素会出现页面被切换的状况。java
简单的测试发现:UC/QQ都与touch事件发生冲突,安卓自带浏览器和谷歌浏览器不会有此现象。touch这个脚本原本就是外国人写的,固然就无视中国特点了。这里对touch作了一些简单的修改,达到避免这种冲突发生。jquery
首先引入zepto(已包含touch)以后,代码以下: git
$('#div').swipeLeft(function(e){ alert(1); })
在PC上用谷歌开发工具模拟器看,没有任何问题。github
在手机上用UC或者QQ看,悲催了,页面直接被滑跑了。你能够试试,体验一下总比别人告诉你印象深入。web
很明显,这里须要阻止默认事件,好比这样改一改: ajax
$('#div').on('touchstart',function(e){ e.preventDefault(); }).swipeLeft(function(e){ alert(1); })
手机上即可以弹出1。而后事情并无结束。api
首先这样写太丑陋了,每一个swipe以前都要去阻止默认事件,更加难以接受的是,这个时候我上下滑动该元素也会阻止默认事件,也就意味着,当页面须要正常上下滚动的时候,手指在该元素上将滑动不了!promise
好吧,那我就去改touch。
首先,找到touch事件快捷绑定的代码块:
;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ $.fn[m] = function(callback){ return this.bind(m, callback) } })
修改以下:
;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ $.fn[m] = function(callback){ if(!this.data('swipeEvents')){ this.data('swipeEvents',m); }else{ this.data('swipeEvents',this.data('swipeEvents')+'|'+m); } return this.bind(m, callback) } })
目的:给全部直接调用swipe的元素,默默的标识上一个数据,该数据就是本元素被绑定的swipe事件的名称,绑定多个swipe时以 | 隔开。
第二步:找到给body绑定的事件冒泡的touchmove事件代码:
.bind('touchmove', function(e){ cancelLongTap() touch.x2 = e.touches[0].pageX touch.y2 = e.touches[0].pageY })
修改成:
.bind('touchmove', function(e){ cancelLongTap() touch.x2 = e.touches[0].pageX touch.y2 = e.touches[0].pageY if(touch.el&&touch.el.data('swipeEvents')){ if(Math.abs(touch.x2-touch.x1)>4&&/Left|Right/.test(touch.el.data('swipeEvents'))){ e.preventDefault(); }else if(Math.abs(touch.y2-touch.y1)>4&&/Up|Down/.test(touch.el.data('swipeEvents'))){ e.preventDefault(); } } })
目的:只要该元素绑定了swipe事件,而且滑动轨迹和swipe事件匹配上,则阻止默认事件。这样,匹配不上的将不被阻止,好比你只是绑定的左右滑动,当touch是上下滑动的时候,不会执行到preventDefault。
通过UC和QQ测试都没有问题。
可是,事情仍是没有结束。由于,你只要换个方式绑定swipe就挂了,好比这样子:
$('#div').on('swipeLeft',function(e){
由于咱们只给$.fn[swipe]的时候作了处理,也就是元素直接调用siwpe方法时,才会有效,一旦调用on方法就嗝屁了。固然,通常元素直接调用swipe就能够了,可是若是想用到事件委托,给大量元素批量绑定的时候就必须用到on啊,这怎么办?很差意思,我这里没有给出好办法,由于on这个方法很差改也不能改,改touch已是心惊胆战了,直接改zepto水平不够。因此暂时还没想到最好的办法,谁知道完美解决办法的请留言。