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

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

来源: 博客园 - Wayne-Zhu

1. 移动端的问题

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

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

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

如何解决这300ms的延迟?

在移动端,最容易想到的就是使用 touchend 来替代 click。但是 touchend 是存在很大问题的,因为 touchend 之前可能是 touchstarttouchmove。具体情境可能是:用户滑动页面时,不小心在一个按钮那里触发了 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 可以看出,有 touchstarttouchend,所以系统会在 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 标签上了。

相关推荐
平头哥技术团队3 分钟前
Day 01 | 用 HTML 写第一个网页:双击就能在浏览器打开
前端
16月6日-晴23 分钟前
Java面向对象——接口
java·开发语言
weixin_4225554232 分钟前
el-menu子菜单点击就被激活,恢复之前的激活状态
javascript·vue.js·elementui
wuyk55538 分钟前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
geovindu38 分钟前
CSharp: Wordcloud
开发语言·后端·c#·.net·.netcore·词云
Java小白笔记1 小时前
Java 实现 ZIP 压缩包生成方案
java·开发语言·网络·7-zip
Persistent的粽子!1 小时前
C++:类与对象(一)
开发语言·c++·经验分享·笔记
计算机魔术师1 小时前
两年翻45倍!英伟达靠买买买建成千亿投资帝国
前端
paopaokaka_luck1 小时前
基于springboot3+vue3的精准扶贫管理系统(AI 问答、ECharts 图形化分析)
前端·人工智能·echarts
weixin_440730501 小时前
使用pytest中方法控制执行步骤(test_begin.py、test_end.py,@pytest.mark.run(order=1))
开发语言·python·pytest