Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

185 - 移动端点击延迟的原因?fast-click解决的原理是什么? #185

Open
bettersong opened this issue Apr 12, 2022 · 0 comments

Comments

@bettersong
Copy link
Owner

bettersong commented Apr 12, 2022

原因

主要是因为移动端事件 touchstart –> touchmove –> touchend or touchcancel –> click,在 touch 事件触发之后,浏览器需要判断用户是否会做出双击屏幕的操作,所以会等待 300ms 来判断,再做出是否触发 click 事件的处理,所以就会有 300ms 的延迟。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Document</title>
</head>
<body>
    <div id="title">测试点击</div>
    <script>
        let t1, t2
        title.ontouchstart = function(e) {
            t1 = +new Date()
            console.log('touchstart')
        }

        title.onclick = function(e) {
            console.log('click', +new Date() - t1)
        }

    </script>
</body>
</html>

image

解决方法

  • meta标签禁止用户缩放
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Document</title>
</head>
<body>
    <div id="title">测试点击</div>
    <script>
        let t1, t2
        title.ontouchstart = function(e) {
            t1 = +new Date()
            console.log('touchstart')
        }

        title.onclick = function(e) {
            console.log('click', +new Date() - t1)
        }

    </script>
</body>
</html>

image
加上 meta标签禁止用户缩放后,点击延迟基本可以忽略

  • 使用插件 fastclick插件解决300ms延迟

原理:FastClick 在 touchend 阶段调用 event.preventDefault,然后通过 document.createEvent 创建一个 MouseEvents,然后通过 event​Target​.dispatch​Event 触发对应目标元素上绑定的 click 事件。

我们可以自己简单实现一下fastclick

// FastClick简单实现
        let targetElement = null;
        title.addEventListener('touchstart', function () {
            // 记录点击的元素
            targetElement = event.target;
        });
        title.addEventListener('touchend', function (event) {
            // 阻止默认事件(屏蔽之后的click事件)
            event.preventDefault();
            let touch = event.changedTouches[0];
            // 合成click事件,并添加可跟踪属性forwardedTouchEvent
            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);
        });

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant