随手记 - 疯狂触发滚轮事件的Mac触控板
头几天官网刚上线,就接到投诉说有问题。过去一看,我靠什么鬼?!Mac下用触控板一滑到底,——首页上用iscroll写的翻页效果直接全军覆没。
这个bug来的莫名其妙,问了一圈人也没什么思路,后来自己上网搜,在一个页面上找到一段关于Mac的触控板的手势滑动会疯狂触发滚轮事件的记录,但是轮到具体的解决方案就语焉不详了。没辙,靠天没用,还是靠自己吧~
这里先简单介绍下。出问题的首页用的是iscroll插件,用snap
属性做的整屏翻页的效果,翻页用鼠标滚轮驱动,这块用的是MDN上的一个滚轮事件的兼容代码,回调使用iscroll的接口完成向上/向下翻页的效果。
回到这个问题上。一开始我想用事件防抖解决,于是用setTimeout()
自己写了个:触发事件后先进入延时,延时后执行函数;如果在延时内仍有事件触发,则取消原有的延时重新计时。
// 打底用的zepto.js,addWheelListener是滚轮事件的兼容插件,下同~ var wheelTimer = false; var wheelSlide = function (e) { e.preventDefault(); clearTimeout(timer); if (e.deltaY > 0) { wheelTimer = setTimeout(function(){ iScroll.next(); }, 100); } else if (e.deltaY < 0 && iScroll.currentPage.pageY != 0) { wheelTimer = setTimeout(function(){ iScroll.prev(); }, 100); } } addWheelListener($('body')[0], wheelSlide);
我本意是用延时抵消掉重复触发的滚轮事件,最后合成一个事件触发,没想到测试之后,Mac上的问题并没有解决。
于是我想,用事件防抖的思路处理应该还是不对,即便是延迟时间较短,如果事件持续触发的话肯定翻页还是会被无限的延迟阻塞掉,至此我想换用事件节流再试试。在找资料的时候,意外发现了Underscore.js这个工具库,里边不仅有现成的节流和防抖(中文文档里用的是“防反跳”)函数可以用,而且还支持链式调用,并且压缩版本也才十几k,正合我意。
说干就干,马上用Underscore撸了个事件节流版的:
var wheelSlide = _(function (e) { e.preventDefault(); if (e.deltaY > 0) { iScroll.next(); } else if (e.deltaY < 0 && iScroll.currentPage.pageY != 0) { iScroll.prev(); } }).throttle(400);//这里毫秒数用了400,大概相当于一个短动画的执行时间 addWheelListener($('body')[0], wheelSlide);
链式写法看上去还挺不错的!进本机浏览器(PC)……嗯?为啥最后会跳一下?赶紧翻文档,又加了个参数上去:
var wheelSlide = _(function (e) { e.preventDefault(); if (e.deltaY > 0) { iScroll.next(); } else if (e.deltaY < 0 && iScroll.currentPage.pageY != 0) { iScroll.prev(); } }).throttle(400, {trailing: false}); addWheelListener($('body')[0], wheelSlide);
这回PC上倒是正常了,Mac也从一滑到底变成了有“段落感”的跳动,但结果还是不对……
一狠心把毫秒数改成了5000,结果呢:还、是、不、对、、、。。。
(//陷入循环懵逼状态ing……)
痛定思痛,一定是文档看的不够多!于是又啃了一遍Underscore.js的文档(虽然是翻译的,囧……),发现防抖居然有个[immediate]
参数,是可以优先执行的!大喜过望~接着撸:
var wheelSlide = _(function (e) { e.preventDefault(); if (e.deltaY > 0) { wScroll.next(); } else if (e.deltaY < 0 && wScroll.currentPage.pageY != 0) { wScroll.prev(); } }).debounce(600, true);// 本来想改回400的,有点心虚所以又加了200…… addWheelListener($('body')[0], wheelSlide);
居然PC和Mac都能一页页的翻页了有!没!有!不过翻页的动作还有点迟滞,于是果断把毫秒数改小:400、200、100,……Bingo!
最终代码:
var wheelSlide = _(function (e) { e.preventDefault(); if (e.deltaY > 0) { wScroll.next(); } else if (e.deltaY < 0 && wScroll.currentPage.pageY != 0) { wScroll.prev(); } }).debounce(50, true); addWheelListener($('body')[0], wheelSlide);
总结:
Mac触控板bug踩坑 +1;
理解了事件节流和事件防抖的概念;
Underscore.js真好用;
感谢git把每次的修改都记了下来。