Auc的个人博客

vuePress-theme-reco Auc    2020 - 2021
Auc的个人博客 Auc的个人博客

选择一个主题吧~

  • 暗黑
  • 自动
  • 明亮
主页
分类
  • JavaScript
  • Vue
  • 数据结构与算法
  • 文档
  • 面试题
  • 笔记
标签
笔记
  • CSS
  • ES6
  • JavaScript
  • Vue
  • C语言
文档
  • Vueのapi
  • Vue Router
  • axios
  • Vue CLI
面试
  • JS
  • Vue
  • 基础
时间线
联系我
  • GitHub (opens new window)
author-avatar

Auc

62

文章

11

标签

主页
分类
  • JavaScript
  • Vue
  • 数据结构与算法
  • 文档
  • 面试题
  • 笔记
标签
笔记
  • CSS
  • ES6
  • JavaScript
  • Vue
  • C语言
文档
  • Vueのapi
  • Vue Router
  • axios
  • Vue CLI
面试
  • JS
  • Vue
  • 基础
时间线
联系我
  • GitHub (opens new window)
  • JavaScritpt

    • 变量的基本类型
    • blur 与 click 冲突
    • 移动端点击穿透
    • 数组快速排序算法 JavaScript 实现

移动端点击穿透

vuePress-theme-reco Auc    2020 - 2021

移动端点击穿透

Auc 2020-01-20 一些坑JavaScript

# 移动端点击穿透

# 问题引入

  • 页面上有一个元素 A 与 B,层级关系是 B 在 A 的上面,但不是嵌套关系;
  • 在 B 元素上注册 touchstart 事件,作用是隐藏 B 元素;A 元素上注册有 click 事件(或者为 a 标签);
  • 问题是:B 元素隐藏后,会将一个事件强行加给下层的 A 元素,发生点击穿透。

# 原因

  1. 触屏设备为了区分用户单双击、缩放,对 click 做了 300ms 延迟触发,这些事件在移动端相应流程为:touchstart ==> touchmove ==> touchend ==> click;

  2. 当触发 B 的 touchstart 事件时,上层 B 隐藏;

  3. 而 300ms 后,看用户在此时间内是否再次触摸屏幕,如果没有 300ms 后,此时弹窗已消失,浏览器在用户手指离开的位置触发 click 事件,所以点到了页面上原本在下层的 B 元素。

# 看一个例子

点击 B 相对于 A 的差集部分,只出触发 B 的 touchstart。

代码如下:

<div id="A"></div>
<div id="B"></div>
<script>
  const A = document.getElementById('A');
  const B = document.getElementById('B');
  A.addEventListener('click', function() {
    console.log('糟糕,事件穿透了');
  });
  B.addEventListener('touchstart', function() {
    console.log('上层 B 的 touchstart 触发');
    B.style.display = 'none';
  });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13

情况来了,当点击 A 于 B 的交集部分,发生了穿透,将 A 的 click 事件也一并触发了。

# 解决方案

# 1. 阻止事件冒泡

在 touch 阶段通过 e.preventDefault() 来阻止后面的 click 触发

B.addEventListener('touchstart', function(event) {
  event.preventDefault();
  console.log('上层 B 的 touchstart 触发');
  B.style.display = 'none';
});
1
2
3
4
5

# 2. 使用延时器

延时 300ms 执行

B.addEventListener('touchstart', function() {
  setTimeout(function() {
    console.log('上层 B 的 touchstart 触发');
    B.style.display = 'none';
  }, 300);
});
1
2
3
4
5
6

# 3. 给上层元素增加动画

在触发 B touchstart 后,不让它立即消失,可以设置一个延时动画大于等于 300ms

$("#B").on("touchstart", function () {
  $(this).fadeOut(300, function () {
    $("#B").remove();
  });
})
1
2
3
4
5

# 4. 使用 FastClick

使用 FastClick 库,本质是检测到 touchend 时,通过 DOM 自定义事件立即触发模拟一个 click 事件,并把浏览器在 300ms 之后真正的 click 事件阻止掉。