移动端tap与click的区别 && 点透事件

移动端tap与click的区别 && 点透事件

来源: 博客园 - Wayne-Zhu

1. 移动端的问题

移动端的主要问题是 click 事件会有 300ms的延迟 。

主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要双击放大,所以,在用户点击的 300ms 之后,才触发 click 事件。如果 300ms 之内还有 click,就会进行放大缩小。

但是,大部分时候放大、缩小是不需要的,开发者也会禁用它们,那么这 300ms 的延迟就是性能上的损耗。

如何解决这300ms的延迟?

在移动端,最容易想到的就是使用 touchend 来替代 click。但是 touchend 是存在很大问题的,因为 touchend 之前可能是 touchstart、touchmove。具体情境可能是:用户滑动页面时,不小心在一个按钮那里触发了 touchend,这样就执行了,但是用户的本意不是如此。

那么该怎么解决呢?

2. tap事件

为了减少这 300ms 的延迟,tap 事件被很多框架(如 Zepto)封装,用来减少延迟问题。tap 事件不是原生的,是封装出来的。

具体是如何实现的呢?主要考虑到下面两点:

  1. 按住的时间不能超过延时时间:因为长时间按住可能就是浏览器的复制、粘贴等操作了。
  2. 不能在页面中移动 :移动是不能触发 tap 事件的。

我们可以自己封装如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tap</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
    <button id="btn">按钮</button>
    <script>
        function tap(ele, callback) {
            // 记录开始时间
            var startTime = 0,
                // 控制允许延迟的时间
                delayTime = 200,
                // 记录是否移动,如果移动,则不触发tap事件
                isMove = false;

            // 在touchstart时记录开始的时间
            ele.addEventListener('touchstart', function (e) {
                startTime = Date.now();
            });

            // 如果touchmove事件被触发,则isMove为true
            ele.addEventListener('touchmove', function (e) {
                isMove = true;
            });

            // 如果touchmove事件触发或者中间时间超过了延迟时间,则返回,否则,调用回调函数。
            ele.addEventListener('touchend', function (e) {
                if (isMove || (Date.now() - startTime > delayTime)) {
                    return;
                } else {
                    callback(e);
                }
            })
        }
        
        var btn = document.getElementById('btn');
        tap(btn, function () {
            alert('taped');
        });
    </script>
</body>
</html>

如上,我们就可以正常使用 tap 事件并且避免了 300ms 延迟的产生。

3. 点透问题 (Ghost Click)

如果我们在移动端所有的 click 都替换为了 tap 事件,还是会触发点透问题。

实质是:

在同一个 z 轴上,z-index 不同的两个元素,上面的元素是一个绑定了 tap 事件的,下面是一个 a 标签。一旦 tap 触发,上面的元素就会 display: none(隐藏或消失)。

从上面的 tap 可以看出,有 touchstart、touchend,所以系统会在 300ms 之后触发 click 事件。此时,上层元素的 z-index 已经消失了,所以,触发了下面 a 标签的 click 事件 (注意:认为 a 标签默认是绑定了 click 事件的)。而这种现象不是我们所期待的。

4. 解决方案

解决点透问题通常有以下两种方案:

(1) 使用 fastclick 库

直接引入 fastclick 库,可以有效解决 300ms 延迟和点透问题。

javascript 复制代码
window.addEventListener("load", function () {
    FastClick.attach(document.body);
}, false);

这样就可以成功解决问题了。

(2) 添加一个延迟

对于上一个 tap 事件做延迟处理,等 300ms 之后再隐藏上层元素。

javascript 复制代码
tap(ele, function () {
    setTimeout(function () {
        ele.style.display = 'none';
    }, 300);
})

这样,过了 300ms 后,click 事件就不会触发在下面的 a 标签上了。

相关推荐
破茧蝴蝶9 小时前
Python分布式爬虫完整教程
开发语言·python
Autumn_ing9 小时前
Design.md生成UI怎么验收?举例运营后台的颜色、状态和数据核对
前端·ui·ai·设计系统·paico·ai生成ui·design.md
狗凯之家源码网10 小时前
全新 PHP 轻量客服聊天室源码深度评测
开发语言·php·聊天室系统
远离UE410 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience10 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
朱涛的自习室10 小时前
我给 Gemini 4 和 DeepSeek 搞了套「末位淘汰」,AI 干活会更猛吗?(Day 3)
android·前端·后端
栈帧之外11 小时前
【C++】STL之set
开发语言·c++
catchadmin12 小时前
免费可商用 PHP 管理后台 CatchAdmin V5.4.1 发布,新增 MCP 支持
开发语言·php
java1234_小锋13 小时前
【技术专题】HTML5 网页技术 - HTML5简介 & HTML5 文档结构
前端·html·html5
jimy113 小时前
c++的 Type Traits (二、更详细版本)
开发语言·c++