移动端网页点击延迟及事件穿透

摘要:
对应的解决方案:1。禁用缩放声明此页面不可缩放,则双击缩放功能没有意义。此时,浏览器可以禁用默认的双击缩放行为,并删除300毫秒的单击延迟。然后浏览器可以认为网站已经针对移动端进行了调整和优化,因此无需双击缩放操作。文档描述html{-ms-touch-action:操纵;touch-action:操纵;}此方案仅在移动端支持chrome和iOS9.3+4。使用fastclick库fastclick的实现思想是使用touchend事件来模拟单击。不建议使用此方法。该方法将导致特定场景中的事件渗透。

一、click事件的300毫秒延迟是怎么产生的?

苹果在2007年发布iphone前夕遇到一个问题,当时相应的网页都是针对大屏编写的,如果直接在iphone上浏览则会出现横向的滚动条,于是他们制定了一些规则来缩放网页,通过双击可以还原网页大小,这种方法后来被其它移动浏览器厂商所采用。300毫秒延迟产生的原因就在于当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

相应的解决办法

1.禁用缩放

<meta name="viewport" content="width=device-width, user-scalable=no">
 
声明这个页面是不可缩放的,那双击缩放的功能就没有意义了,此时浏览器可以禁用默认的双击缩放行为并且去掉300ms的点击延迟。
这个方案有一个缺点,就是必须通过完全禁用缩放来达到去掉点击延迟的目的,然而完全禁用缩放并不是我们的初衷,我们只是想禁掉默认的双击缩放行为,这样就不用等待300ms来判断当前操作是否是双击。但是通常情况下,我们还是希望页面能通过双指缩放来进行缩放操作,比如放大一张图片,放大一段很小的文字。
 
2.更改默认的视口宽度
<meta name="viewport" content="width=device-width">

为了让桌面站点能在移动端浏览器正常显示,移动端浏览器默认的视口宽度并不等于设备浏览器视窗宽度,而是要比设备浏览器视窗宽度大,通常是980px。我们可以通过上面的标签来设置视口宽度为设备宽度。那浏览器就可以认为该网站已经对移动端做过了适配和优化,就无需双击缩放操作了。
这个方案相比方案一的好处在于,它没有完全禁用缩放,而只是禁用了浏览器默认的双击缩放行为,但用户仍然可以通过双指缩放操作来缩放页面。

3.css3的touch-action

touch-action这个CSS属性。这个属性指定了相应元素上能够触发的浏览器的默认行为。文档说明

html {
    -ms-touch-action: manipulation;
    touch-action: manipulation;
}  

该方案只支持移动端的chromiun 和 iOS 9.3+

4、使用fast click库

fastclick的实现思路是使用touchend事件来模拟click,不推荐该方法,该方法在特定场景下会导致事件穿透。

FastClick.prototype.onTouchEnd = function(event){

  // 一些状态监测代码 

  // 从这里开始,
  if (!this.needsClick(targetElement)) {
    // 如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click
    event.preventDefault(); 
    // 触发一次模拟的click
    this.sendClick(targetElement, event);
  }
}
FastClick.prototype.sendClick = function(targetElement, event) {

  // 这里是一些状态检查逻辑

  // 创建一个鼠标事件
  clickEvent = document.createEvent('MouseEvents');
  // 初始化鼠标事件为click事件
  clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);

  // fastclick的内部变量,用来识别click事件是原生还是模拟
  clickEvent.forwardedTouchEvent = true;

  // 在目标元素上触发该鼠标事件,
  targetElement.dispatchEvent(clickEvent);
}

二、事件穿透

1.现象描述

假如页面上有两个元素A和B。B元素在A元素之上。我们给B元素的touchstart或touchend绑定一个回调函数,该回调函数的作用是隐藏B元素,当触摸B元素,B元素被隐藏了,随后,A元素触发了click事件。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
   .mask{
     width: 200px;
     height: 100px;
     background-color: gold;
   }
   .top{
     width: 100px;
     height:100px;
     background-color: gray;
     position: absolute;
     top:0;
     left: 0;
   }
  </style>
</head>
<body>
<div class="mask" id="bottom">我是底层</div>
<div class="top" id="top">我是上层</div>
<script>
  window.onload=function(){
    document.getElementById("bottom").onclick=function(){
      alert('我是底层');
    }
    document.getElementById("top").ontouchend=function(){
       this.style.display='none';
    }
  }
</script>
</body>
</html>

 2.产生的条件

上层元素采用touchstart或touchend,下层元素有click事件或是一个指定了href的超链接,上层元素在触摸后不可见

3.产生的原因

 在移动端浏览器,事件执行的顺序是touchstart > touchend > click,touch事件结束后会等待300毫秒,然后执行click事件。

上面的例子中touchend把上层元素隐藏之后,隔了300ms,浏览器触发了click事件,但是此时上层元素不见了,所以该事件被派发到了底层元素身上。如果底层元素是一个链接,那此时页面就会意外地跳转。

4.如何解决

网上搜到的meta头禁用缩放,css3的touch-action这两种方法都是瞎扯蛋,经实验,可行的方法如下:

4.1 统一使用touch事件( touchstart 、’touchend’),然后上层元素隐藏后使用event.preventDefault(),要不然下层元素如果是a标签,a标签的href也是click行为

4.2 如果不需要判断触摸手势等,可以把页面内所有的touch换成click,然后采用第一节中的方案来解决click延迟

4.3 遮挡法:动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,也不会“穿透”到底下

4.4 延迟法:给消失的元素做一个fade效果,类似jQuery里的fadeOut,并设置动画duration大于300ms,这样当延迟的 click 触发时,就不会“穿透”到下方的元素了。

4.5下层元素使用pointer-events属性,上层元素隐藏时将下层元素的pointer-events设为none,然后400ms后把该属性恢复成auto。该方法的问题在于必须要知道可能受影响的下层元素有哪些,实际项目中意义不大

  window.onload=function(){
    document.getElementById("bottom").onclick=function(){
      alert('我是底层');
    }
    document.getElementById("top").ontouchend=function(e){
       this.style.cssText="display:none;"
       var bottom=document.getElementById("bottom");
       bottom.style.cssText="pointer-events:none";
       setTimeout(function(){
        bottom.style.cssText="pointer-events:auto";
       }, 400);
    }
  }

免责声明:文章转载自《移动端网页点击延迟及事件穿透》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇引领Boost(五)(Boost::array)ESP8266的低功耗方案-睡眠模式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

移动端布局2:vw结合rem实现移动端布局

上一回说到了媒体查询结合rem做移动端布局,步骤如下 首先设置媒体查询,确定html中font-size值的变化 @media all and (max-320px){ html{font-size:12px;} } @media all and (min-321px) and (max-375px){ html{font...

移动端去除横向滚动条

移动端横向商品浏览、横向滑动广告位(CSS实现) 在手机上逛一些电商网站或者其他相同类型的网站时,会遇到横向滑动的商品。如京东、淘宝等电商网站下。我们知道,这一般情况下为某个元素设置overflow: auto做到,表示横向或者竖向依据内容的多少自动出现滚动条。但是,在页面中间出现横向滚动条是十分不好看的..在不使用任何插件的情况下,可以使用原生CSS的...

移动端css、Js优处理

CSS 篇 0.5px细线 移动端 H5 项目越来越多,设计师对于 UI 的要求也越来越高,比如 1px 的边框。在高清屏下,移动端的 1px 会很粗。 那么为什么会产生这个问题呢?主要是跟一个东西有关,DPR(devicePixelRatio) 设备像素比,它是默认缩放为 100%的情况下,设备像素和 CSS 像素的比值。目前主流的屏幕 DPR=2(...

移动端及vue相关问题

1-pc端与移动端  PC下,html在默认情况下以可视区域宽度为基准。移动设备没有适配时,html宽度为980. 2-1像素还原 获取像素比: window.devicePixelRatio 计算缩放比:1 / window.devicePixelRatio 3-单位 px:固定值,绝对单位;%:相对单位;em:相对单位,相对于自身或者父级元素字体大小计...

69、移动端布局-媒体查询 + rem单位布局

现在HTML5前端不仅仅局限于PC端,HTML5前端还可以实现移动端,实现微信等等,传统的布局单位px,不能是达到自适应的学校过,那么移动端布局有哪些方式呢? 媒体查询 + rem单位布局 说道这个布局,,那么我们首先得了解什么是媒体查询,rem是什么? 媒体查询:媒体查询可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其设定...

React 还是 Vue: 你应该选择哪一个Web前端框架?

2016年,React在Web端和移动端都实现了迅速的成长,稳稳地领先于其主要竞争对手Augular,巩固了其作为前端框架之王的地位。 但是Vue在这一年里的表现也可谓同样的耀眼。Vue.js 2.0 的发布在整个JavaScript社区都引起了巨大反响,这一点仅从它在Github中涨了25,000颗star,就足以得到证明。 不得不说React和Vue...