触屏网页防止误点击(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产生问题。

发表回复