由移动端页面点击穿透想到的

原文链接 http://ymblog.net/2016/03/28/由移动端页面点击穿透想到的/

首先我想到了哪些:

  1. 点击穿透是如何引起的
  2. 如何解决
  3. 什么是事件模拟

一、点击穿透是如何引起的?

可能是由click事件的延迟或者事件冒泡导致,事件包含touchstart/touchmove/touchend/mousedown/mousemove/mouseup/click。

造成点击穿透的原因是,在移动端页面中click的点击事件有200-300ms的延迟,为了体验更好我们使用了zepto的touch事件,或者说使用的touchstart/touchend事件,在执行完 touch事件之后,目标事件执行,此时 click 事件还在延迟的 300ms 之中。当 300ms 到来的时候,click 到的其实是隐藏元素下方的元素。

如果正下方的元素有绑定 click 事件,此时便会触发,如果没有绑定 click 事件的话就当没发生。如果正下方的是 input 输入框(或是 select / radio / checkbox),点击默认 focus 而弹出输入键盘,也就出现了上面的“点透”现象。

那为什么要有延迟?浏览器在 touchend 后会等待约300ms,原因是判断用户是否有双击(double tap)行为。如果没有 tap 行为,则触发 click 事件,而双击过程中就不适合触发 click 事件了。由此可以看出 click 事件触发代表一轮触摸事件的结束。

DOM事件流:

1,事件捕获阶段;

2,处于目标阶段;

3,事件冒泡阶段。

说到这儿我们再来了解下事件的执行顺序,在移动端页面中,touch事件的执行顺序是touchstart ->touchmove -> touchend -> mousedown ->mouseup ->click,当然在web端中可能顺序又不一样。

那似乎上面说的穿透问题变得理所当然了。因为这是浏览器的默认行为!

二、如何解决

一般来说加上下面的代码就会解决问题了。

在touchend事件中阻止浏览器的默认行为,就可以了。

event.preventDefault();

 

上面的算是一种解决办法了,我记得还会有那种情况即使加了这行语句还是无效的更特殊的情况,有人说使用fastclick可以解决问题,当初我使用的时候发现确实好像点击快了很多,但是在华为荣耀3C的机型上却发现还是会出现点击穿透的现象,再考虑到为此我需要再引入一个文件的http的请求,所以果断放弃。

还有一种治标不治本的方式,如下:

由于 click 事件的滞后性,在这段时间内原来点击的元素消失了,于是便“穿透”了。因此我们顺着这个思路就想到,可以给元素的消失做一个fade效果,类似jQuery里的fadeOut,并设置动画duration大于300ms,这样当延迟的 click 触发时,就不会“穿透”到下方的元素了。

同样的道理,不用延时动画,我们还可以动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,也不会“穿透”到底下。在一定的timeout后再将生成的透明元素移除。

$(‘#closePopup‘).on(‘tap‘, function(e){
    $(‘#popupLayer‘).hide();
    $(‘#bgMask‘).hide();

    $(‘#underLayer‘).css(‘pointer-events‘, ‘none‘);

    setTimeout(function(){
        $(‘#underLayer‘).css(‘pointer-events‘, ‘auto‘);
    }, 400);
});

  

但如果页面中的点击事件多了这样肯定不行的。

三、什么是事件模拟

zepto上的tap事件也是模拟出来的,我们似乎可以自己来模拟点击事件。

我们可以打印控制台打印的event对象,

所谓事件模拟就是通过特定的方法,传入指定的参数,然后派发这个自定义事件就可以了。

var event = document.createEvent(‘MouseEvents‘);

  

这个参数可选的有:

  1. UIEvents
  2. MouseEvents
  3. MutationEvents,一般化dom变动
  4. HTMLEvents一般dom事件
var type = ‘click‘; //要触发的事件类型
var bubbles = true; //事件是否可以冒泡
var cancelable = true; //事件是否可以阻止浏览器默认事件
var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管
var detail = 0;
var screenX = 0;
var screenY = 0;
var clientX = 0;
var clientY = 0;
var ctrlKey = false; //是否按下ctrl
var altKey = false; //是否按下alt
var shiftKey = false;
var metaKey = false;
var button = 0;//表示按下哪一个鼠标键
var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象

var event = document.createEvent(‘MouseEvents‘);
event.initMouseEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY,
ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);

  

最终的解决办法:

var el = null;
var list = document.getElementById(‘list‘);
function getEvent(el, e, type) {
    e = e.changedTouches[0];
    var event = document.createEvent(‘MouseEvents‘);
    event.initMouseEvent(type, true, true, window, 1, e.screenX, e.screenY, e.clientX, e.clientY, false, false, false, false, 0, null);
    //event.forwardedTouchEvent = true;
    return event;
}
list.addEventListener(‘touchstart‘, function (e) {
    var firstTouch = e.touches[0]
    el = firstTouch.target;
})
list.addEventListener(‘touchend‘, function (e) {
    e.preventDefault();
    var event = getEvent(el, e, ‘click‘);
    el.dispatchEvent(event);
})
list.addEventListener(‘click‘, function (e) {
    list.style.display = ‘none‘;
    setTimeout(function () {
        list.style.display = ‘‘;
    }, 1000);
})

  

我们可以在touchend事件的时候阻止浏览器的默认行为,然后自己模拟事件的产生与触发。这就是自己创建一个click的Event对象触发之,所有的点击依然就用click。

四、总结

从早上看资料看到现在,刚开始思路还非常清晰,问题的来源,问题的产生等等以及该如何解决...看的时间久了,看的东西多了突然发现变得模糊了起来,发现很多东西都是冲突的,比如点击穿透是zepto引起的?看了下网友说的,由于zepto的模拟tap事件是冒泡到document才触发的,而在冒泡到 document 之前,手指接触和离开屏幕(touchstart / touchend)是会触发 click 事件的。所以就会有这个问题?那我阻止了浏览器的默认事件不就ok了?

但似乎又是说在安卓和iOS的区别在于mousedown的执行速度,安卓大于iOS

在android上获得的结果是惊人的,这个劳什子android里面moveover事件偶然比尼玛touchstart还快!!!

而ios压根就不理睬mouseover事件,这是主要问题产生原因!!!

而android在movedown时候,开开心心触发了input的focus事件,然后键盘就弹起来了!!!

所以针对android,我们还得将mousedown干掉才行!!!!

而事实上,我们input获取焦点,就是通过mousedown触发的,ios也是,所以要解决android下面的问题还得从其它层面抓起

这也就产生了最终的解决办法:也就是上面写的,上面的只是针对一个点击事件,下面则针对全部:

var touch = {};
var t = new Date().getTime();
document.addEventListener(‘click‘, function (event) {
        if (event.myclick == true) {
            return true;
        }
        if (event.stopImmediatePropagation) {
            event.stopImmediatePropagation();
        } else {
            event.propagationStopped = true;
        }
        event.stopPropagation();
        event.preventDefault();
        return true;
    }, true);

    document.addEventListener(‘touchstart‘, function (e) {
        touch.startTime = e.timeStamp;
        touch.el = e.target;
        t = e.timeStamp;
    });
    document.addEventListener(‘touchmove‘, function (e) { });
    document.addEventListener(‘touchend‘, function (e) {
        touch.last = e.timeStamp;
        var event = document.createEvent(‘Events‘);
        event.initEvent(‘click‘, true, true, window, 1, e.changedTouches[0].screenX, e.changedTouches[0].screenY, e.changedTouches[0].clientX, e.changedTouches[0].clientY, false, false, false, false, 0, null);
        event.myclick = true;
        touch.el && touch.el.dispatchEvent(event);
        return true;
    });

    dom.addEventListener(‘click‘, function (e) {
        alert(1);
    });

  

其核心是自己模拟事件并派发。

var event = document.createEvent(‘Events‘);
event.initEvent(‘click‘, true, true, window, 1, e.changedTouches[0].screenX,
e.changedTouches[0].screenY, e.changedTouches[0].clientX, e.changedTouches[0].clientY, false, false, false, false, 0, null);
event.myclick = true;
touch.el && touch.el.dispatchEvent(event);

五、参考

最先点开的这篇文章:https://segmentfault.com/q/1010000000691822

后来又点开了这篇文章:https://segmentfault.com/a/1190000003848737

然后在这篇文章的页脚又看到了很多,于是乎又查看了这篇:http://www.cnblogs.com/yexiaochai/p/3462657.html

然后又看了这篇:http://www.cnblogs.com/yexiaochai/p/3442220.html

时间: 2024-10-11 13:08:49

由移动端页面点击穿透想到的的相关文章

移动页面点击穿透问题解决方案

移动页面点击穿透问题解决方案 时间 2015-08-24 21:43:58  黯羽轻扬 原文  http://www.ayqy.net/blog/移动页面点击穿透问题解决方案/ 主题 JavaScript 一.click与300ms延迟 移动浏览器提供一个特殊的功能:双击(double tap)放大 300ms的延迟就来自这里,用户碰触页面之后,需要等待一段时间来判断是不是双击(double tap)动作,而不是立即响应单击(click),等待的这段时间大约是300ms.之前有过简单介绍: 黯羽

移动页面的点击穿透问题

点击穿透现象有3种: 点击穿透问题:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件 蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,touch事件触发之后,蒙层消失了,300ms后这个点的click事件fire,event的target自然就是按钮下面的元素,因为按钮跟蒙层一起消失了 跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转 因为 a标签跳转默认是click事件触发 ,所以原理和上面的完

点击穿透问题(http://www.tuicool.com/articles/6NfaUnM)

一.click与300ms延迟 移动浏览器提供一个特殊的功能:双击(double tap)放大 300ms的延迟就来自这里,用户碰触页面之后,需要等待一段时间来判断是不是双击(double tap)动作,而不是立即响应单击(click),等待的这段时间大约是300ms.之前有过简单介绍: 黯羽轻扬:HTML5触摸事件 移动事件提供了 touchstart . touchmove . touchend 却没有提供tap支持,主流框架(库)都是手动实现了自定义tap事件,以求消除300ms延迟,提高

移动端300ms点击延迟和点击穿透问题

一.移动端300ms点击延迟 一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟.也就是说,当我们点击页面的时候移动端浏览器并不是立即作出反应,而是会等上一小会儿才会出现点击的效果.在移动WEB兴起的初期,用户对300ms的延迟感觉不明显.但是,随着用户对交互体验的要求越来越高,现今,移动端300ms的点击延迟逐渐变得明显而无法忍受. 那么,移动端300ms的点击延迟是怎么来的呢? 问题由来 这要追溯至 2007 年初.苹果公司在发布首款 iPho

点击穿透原理及解决

一.事件触发顺序 PC网页上的大部分操作都是用鼠标的,即响应的是鼠标事件,包括mousedown.mouseup.mousemove和click事件.一次点击行为,可被拆解成:mousedown -> mouseup -> click 三步. 手机上没有鼠标,所以就用触摸事件去实现类似的功能.touch事件包含touchstart.touchmove.touchend,注意手机上并没有tap事件.手指触发触摸事件的过程为:touchstart -> touchmove -> tou

教会你开发移动端页面的文章(二)

之前分享过一篇文章<教会你开发移动端页面的文章(一)>.那是本篇文章的基础,如果没有阅读过的同学可以去看看,今天就给大家带来干货,真真正正的讲到如何很好的开发一个移动端的页面 好了,让我们开始吧,从哪里开始呢?从设计图开始,即PSD稿件:移动端PSD稿件的尺寸肯定较之PC端的PSD稿件不同,具体体现在设计图的尺寸上,现在移动端的设计图尺寸大多以iPhone5和iPhone6的设备像素尺寸作为依据,比如拿到一张PSD设计图,它的总宽度为640px(iPhone5)或者750px(iPhone6)

移动端页面开发

移动端页面开发 移动客户端的开发类型(站在前端立场上来说),主要是三种:Native App(原生APP),也就是完全使用移动设备系统语言写的客户端,iPhone iPad就是纯Object-C,安卓就是纯JAVA, 是性能最棒的开发方式,但灵活性不好.Web App, 就是在移动浏览器里打开的,纯HTML+CSS+JS,说白了就是个网页,只不过非常的富应用,比如手机浏览器访问的GMAIL.就是在浏览器里打开的页面.IOS支持可以在桌面创建访问的快捷方式,但是说到底还是打开Safari跑.而且对

移动端页面开发流程

移动端页面布局 一.移动端app分类 1.Native App原生app手机应用程序 使用原生的语言开发的手机应用,Android系统用的是java,ios系统用的是object-C 2.Hybrid App 混合型app手机应用程序 混合使用原生的程序和html5页面开发的手机应用 3.Web App 基于Web的app手机应用程序 完全使用html5页面加前端js框架开发的手机应用 二.Viewport视口 视口是移动设备上用来显示网页的区域,一般会比移动设备可视区域大,宽度可能是980px

移动端页面布局的那些事儿

移动端页面布局的那些事儿 http://www.xiaoxiangzi.com/Programme/CSS/4298.html 一. viewport 什么是viewport 简单来讲,viewport就是浏览器上,用来显示网页的那一部分区域了,也就是说,浏览器的实际宽度,是和我们手机的宽度不一样的,无论你的手机宽度是320px,还是640px,在手机浏览器内部的宽度,始终会是浏览器本身的viewport.如今的浏览器,都会给自己的本身提供一个viewport的默认值,可能是980px,或者是其