移动端之300ms延迟

原因

无键盘全触屏手机初期,页面全是为PC端设计的(没有设置<meta name="viewport">),iPhone作为全触屏手机始祖,为了便于用户浏览网页引入了双击缩放功能。手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。如何判断用户是单击还是双击?当用户点击屏幕时,会等待300ms,如果300ms内再次点击,则判定为双击,如果300ms内没有再次点击,则判定为单击。所以如果用click监听用户点击链接或元素,click事件会在300ms后再触发。

现象

<!DOCTYPE html>
<html>

<head>
    <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
    <meta charset="utf-8">
    <title>JS Bin</title>
    <style>
        body {
            font-size: 60px;
        }
    </style>
</head>

<body>
    <div id="delay">有延迟</div>
    <div id="no-delay">无延迟</div>
    <a id="link1" href="#1">链接1</a>
    <a id="link2" href="#2">链接2</a>
    <div id="log"></div>
    <script>
        const log = str => $('#log').innerText = str;
        const $ = s => document.querySelector(s)

        let t1, t2;
        $("#delay").ontouchstart = function () {
            t1 = Date.now(); //记录点击事件
            console.log(t1);
        }
        $("#delay").onclick = function () {
            log(Date.now() - t1); //打印出click触发时间,会延迟300ms左右
            console.log(222);
        }
        $('#no-delay').ontouchstart = e => {
            log('touchstart无延迟')
        }

        $('#link1').ontouchstart = e => {
            t2 = Date.now()
        }

        $('#link2').ontouchstart = e => {
            t2 = Date.now()
        }

        window.onhashchange = () => {
            log(`link ${location.hash} : ${Date.now() - t2}ms`)
        }
    </script>
</body>

</html>

上面代码,KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲delay").ontouch…("#delay").onclick 记录了click被触发的时间,#log打印出延迟时间,一般在300ms左右。也就是说click事件被触发事件比用户触摸屏幕事件晚300ms,这样会造成一种延迟、不顺畅的感觉,体验不好。

解决

  1. 设置meta:
    <meta name="viewport" content="width=device-width">,经过测试,在android手机只要添加name=viewport的meta即可消除延迟, 在ios上必须设置width=device-width。 一般做移动端自适应都会加上这句话,所以大部分情况下,加上这句话就能解决问题。
  2. 其他方法:fastclick库(目前也不经常使用,因为大部分情况下,第一种方式能解决问题),或者不用click用touchstart(不推荐,用户滑动页面也会触发touchstart,又会产生新问题)。

fastcilck

  1. 原理:在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后真正的click事件阻止掉。
  2. 简单实现:
const FastClick = (function(){

      function attach(root) {
        let targetElement = null
        root.addEventListener('touchstart', function () {
          targetElement = event.target
        })
        root.addEventListener('touchend', function (event) {
          event.preventDefault()
          let touch = event.changedTouches[0]
          let clickEvent = document.createEvent('MouseEvents')
          clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null)
          clickEvent.forwardedTouchEvent = true 
          targetElement.dispatchEvent(clickEvent)
        })        
      }

      return { attach }
    })()
    FastClick.attach(document.body)

说明

即便解决了300ms延迟,click事件的触发还是会有一定延迟。原因:事件的触发顺序为touchstart -> touchend -> click,也就是说用户手指离开屏幕才触发click,用户点击到手指离开总有个间隔,所以总会有一点延迟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值