简要的探讨一下移动端 touch 事件处理几个坑,以及相应的简单处理方法。git
假设有个弹出层,上面有个关闭的按钮支持 touchend 触发后关闭,若正好下方有个元素支持 click 事件,在弹出层关闭后将会在下方元素触发 click 事件。这种效果确定不是咱们须要的,并且咱们没法肯定合适会在上方出现一个支持 touch 的弹出层,因此我认为最好的处理方式是禁用全部元素的 click 事件,相比 click 须要长达 1s 的触发时间,使用 touchend 能够得到更好的体验。github
一个正确的 tap 事件应当知足一下条件:web
具体实现代码能够参考 tap-event。app
Android 4.0 如下是不支持原生的 webview 滚动的,因此只能使用 iscroll 之类的工具来模拟元素滚动。它的缺点就是有些过于的复杂,因此我仍是会在条件容许的状况下使用原生的滚动。函数
启用原生滚动只须要给外层元素加上样式 -webkit-overflow-scrolling: touch;
便可,若是你的监听函数比较占用资源咱们能够经过一个简单的 buffer 函数来限制它的触发间隔,例如:工具
function buffer(fn, ms) { var timeout; return function() { if (timeout) return; var args = arguments; timeout = setTimeout(function() { timeout = null; fn.apply(null, args); }, ms); } } document.querySelector('.scrollable').onscroll = buffer(onScroll, 100);
另外的建议就是不要在可滚动元素上使用阴影样式(text-shadow 和 box-shadow),由于它们很是影响性能,并且看上去也不怎么美观。性能
还有须要注意的是若是你须要启用apple-mobile-web-app-capable
, 注意将apple-mobile-web-app-status-bar-style
设置为black-translucent
,不然会出现还差 22 像素滚动不到头的坑爹 bug。code
IOS下默认状况下用户的拖动操做在scroll滚到头之后会致使总体页面的滚动,一种方式是禁用掉 document 的 touchmove 原生触发component
document.addEventListener('touchmove', function(e) { e.preventDefault(); });
此时原生的滚动是没法工做的,解决办法就是禁用滚动元素的 touchmove 事件冒泡事件
scrollable.addEventListener('touchmove', function (e) { e.stopPropagation(); });
另外一种方式是断定滚动元素滚到头以后禁用掉默认的处理
var el = document.querySelector('.scrollable'); var sy = 0; events.bind(el, 'touchstart', function (e) { sy = e.pageY; }) events.bind(el, 'touchmove', function (e) { var down = (e.pageY - sy > 0); //top if (down && el.scrollTop <= 0) { e.preventDefault(); } //bottom if (!down && el.scrollTop >= el.scrollHeight - el.clientHeight) { e.preventDefault(); } })
我我的倾向于第二种方案,由于若是单纯的禁用 document 的 touchmove 监听,会致使一些处理的失效,好比说上面提到的 tap-event
模块。
经过 event 的 pageX 和 pageY 属性便可计算,可参考 hammer.js