触屏网页防止误点击(ghostClick)
如果在触屏的网页中,你为一个dom元素绑定'touchstart','touchend'事件来实现点击互动,那么如果你拖动屏幕时触摸到这个dom也会触发这两个事件,因为move的过程中也会执行start和end,这违背了我们的交互需要。
显然,我们要想办法规避这个问题。
如果你用jqueryMobil或者zepto,只要用里面针对触屏的事件,是不会碰到这个问题的。
基本思路就是重写了触发的的方法,根据条件来判断当前事件状态,在'touchend'的时候来决定当前用户是用了点击还是用了移动。
如果不想引入类库要怎么做。
我们增加一个函数MBP(全称为Mobile Boilerplate,该点击事件函数是该项目中的一部分)。
整个函数参考《HTML5移动Web开发实践》四章9节的代码内容
但是书里的内容有些问题,我对里面的内容做了一些修改,我们看下面代码。
函数部分
(function(document){//防止误点击 window.MBP = window.MBP || {}; MBP.fastButton = function (element, handler) {//函数入口 this.element = element; this.handler = handler; if (element.addEventListener) {//这里对选用的触发事件做了区分,保证触屏和非触屏用的是不同的事件绑定。 if (document.hasOwnProperty("ontouchstart")) { element.addEventListener('touchstart', this, false); }else{ element.addEventListener('click', this, false); } } }; MBP.fastButton.prototype.handleEvent = function(event) {//监听触发事件类型 switch (event.type) { case 'touchstart': this.onTouchStart(event); break; case 'touchmove': this.onTouchMove(event); break; case 'touchend': this.onClick(event); break; case 'click': this.onClick(event); break; } }; MBP.fastButton.prototype.onTouchStart = function(event) { //onTouchStart方法监听touchmove和touchend事件,Stoppropagation函数用来防止事件在监听中传递,阻止冒泡,即只在当前方法体内寻找当前事件的监听器 event.stopPropagation(); this.element.addEventListener('touchend', this, false); document.body.addEventListener('touchmove', this, false); this.startX = event.touches[0].clientX; this.startY = event.touches[0].clientY; }; MBP.fastButton.prototype.onTouchMove = function(event) {//如果触摸偏移10像素以上判断为move事件 if(Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10 ) { this.reset(); } }; MBP.fastButton.prototype.onClick = function(event) {//如果不是其他可能,执行事件 event.stopPropagation(); this.reset(); this.handler(event); if(event.type == 'touchend') { MBP.preventGhostClick(this.startX, this.startY); } }; MBP.fastButton.prototype.reset = function() {//核心方法,移除move和touched的事件,以保证做正确的事件 this.element.removeEventListener('touchend', this, false); document.body.removeEventListener('touchmove', this, false); }; MBP.preventGhostClick = function (x, y) { MBP.coords.push(x, y); window.setTimeout(function (){ MBP.coords.splice(0, 2); }, 2500); }; MBP.ghostClickHandler = function (event) {//这部分是对不支持touch事件设备的兼容 for(var i = 0, len = MBP.coords.length; i < len; i += 2) { var x = MBP.coords[i]; var y = MBP.coords[i + 1]; if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) { event.stopPropagation(); event.preventDefault(); } } }; if (document.addEventListener) {//为文档中其他click事件添加防止误点击操作 document.addEventListener('click', MBP.ghostClickHandler, true); } MBP.coords = []; })(document);
如何使用
var btn = document.getElementById('domId'); btnTouch = new MBP.fastButton(btn,function(){alert('点击成功')});
关于触摸事件的延伸——点透问题
在移动设备中用了触摸点击事件会产生一系列的点透问题,可以转到我文章中的《关于移动设备“点透”的问题》查看解决方法。
其他补充
不要在该方法生成的事件中添加alert事件,不然在ios(我的环境是ios6)中触发后会在下一次触摸屏幕的时候触发touchstart事件,执行未被销毁的alert产生问题。