【原】移动端vue页面点透事件 - 分析与解决

2024-01-20 22:48

本文主要是介绍【原】移动端vue页面点透事件 - 分析与解决,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

近期项目遇到了vue页面事件被带到下一个页面的问题,也就是我们常说的点透事件,主要表现在android机器上,花了不少时间折腾,简单做下总结~

  • vue页面之间的切换通过Vue Router的router.push方法
  • b.vue之前已经访问过,数据通过vuex管理,从a.vue进入到b.vue不再请求数据,直接拿到b.vue数据展示页面;
  • a.vue页面上点击最底部的账单后,不到100ms就打开b.vue页面,此时最底部的账单的触摸事件并没有消失,a.vue的触摸事件直接平移到b.vue最底部位置,刚好最底部有个按钮,导致直接打开c.vue。

验证是否因为300ms延迟导致的问题

早在2013做移动端页面时候就听说过点透事件,由click事件引起的300ms的延迟导致:

移动设备上的web网页是有300ms延迟的,往往会造成按钮点击延迟,引起页面点透或是点击失效。

2007年苹果发布首款iphone上IOS系统搭载的safari为了将适用于PC端上大屏幕的网页能比较好的展示在手机端上,使用了双击缩放(double tap to zoom)的方案,比如你在手机上用浏览器打开一个PC上的网页,你可能在看到页面内容虽然可以撑满整个屏幕,但是字体、图片都很小看不清,此时可以快速双击屏幕上的某一部分,你就能看清该部分放大后的内容,再次双击后能回到原始状态。

双击缩放是指用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。

原因就出在浏览器需要如何判断快速点击上,当用户在屏幕上单击某一个元素时候,例如跳转链接<a href="#"></a>,此处浏览器会先捕获该次单击,但浏览器不能决定用户是单纯要点击链接还是要双击该部分区域进行缩放操作,所以,捕获第一次单击后,浏览器会先Hold一段时间t,如果在t时间区间里用户未进行下一次点击,则浏览器会做单击跳转链接的处理,如果t时间里用户进行了第二次单击操作,则浏览器会禁止跳转,转而进行对该部分区域页面的缩放操作。那么这个时间区间t有多少呢?

在IOS safari下,大概为300毫秒。这就是延迟的由来。造成的后果用户纯粹单击页面,页面需要过一段时间才响应,给用户慢体验感觉,对于web开发者来说是,页面js捕获click事件的回调函数处理,需要300ms后才生效,也就间接导致影响其他业务逻辑的处理。

事隔7年,浏览器厂商还没修复这个问题么?楼主使用iPhone X、华为、vivo、小米等主流的手机来测试。

首先我们在移动端网页使用双击缩放模式(不设置viewport)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
<script type="text/javascript" class="library" src="https://cdn.bootcss.com/zepto/1.1.7/zepto.js"></script>
<style type="text/css">#btn{margin: 50px 0;width: 200px;height: 40px;text-align: center;font-size: 16px;}
</style>
</head>
<body><button id="btn">点我查看事件响应时间</button><script type="text/javascript">let startTime;let log = function (msg) {let div = $('<div></div>');div.html((new Date().getTime()) + ': ' + (new Date().getTime() - startTime) + ': ' + msg)$('body').append(div);};let touchStart = function () {startTime = new Date().getTime();log('touchStart');};let touchEnd = function () {log('touchEnd');};let click = function () {log('click');};let mouseUp = function () {log('mouseUp');};let mouseDown = function () {log('mouseDown');};let btn = $('#btn');btn.bind('touchstart', touchStart);btn.bind('touchend', touchEnd);btn.bind('mousedown', mouseDown);btn.bind('mouseup', mouseUp);btn.bind('click', click);
</script>
</html>

对应日志如下,可以看到没有添加viewport的情况,ios可以看到click事件300ms的延迟问题还是存在,Android表现正常。

接着,页面添加viewport:<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">的情况,ios和android触发事件后打印的日志并没有300ms延迟。

从上面结果看出300ms的延迟主要表现在没有设置viewport的ios手机上,H5页面我们一般会设置viewport:<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">

所以楼主认为我们正常的H5页面中click事件是不存在300ms延迟的情况

那Android手机上点透事件到底怎么回事呢?

为了进一步验证不是300ms延迟引起的问题,采用互联网常见的防点透方案来解决问题:

比较流行的解决方案有v-tap或vue2-touch-events自定义的tap事件,原理是把三个基础触摸事件:touchstart、touchmove、touchend组合起来叫tap事件,不使用click。

然而,经过反复测试后不能解决问题,所以楼主猜想本次点透并不是300ms引起的。

还有一种解决点透的方案是添加透明遮罩层,通常在跳转的下一个页面上,有一个透明遮罩层置于最顶层,从上一个页面平移的事件不能触发当前页面的事件,然后过300ms后再隐藏该遮罩层,以此来阻止点透,可以暴力解决点透问题。

检查了这次项目中代码的HTML结构,其中包含touchstart、touchmove、touchend 、click 4个事件,测试发现click事件的代码并没有起作用,

<template>
<divclass="item"@touchstart="touchStart"@touchmove="touchMove"@touchend="touchEnd"@click="clickItem"
><slot :data="item"></slot>
</div>
</template>

 因为touchend触发后有个路由的方法router.push让页面跳转了,click事件并没有生效,也就是touchend后页面A把事件带到了页面B上,又刚好命中页面B上的按钮,从而导致页面C被打开的点透效果!

touchEnd: function (event) {this.$emit('goToDetail')//跳转detail页面
}

发现原因:元素touchend之后触发浏览器默认行为导致点透

猜测给div标签绑定touchend事件后,元素有了浏览器默认的行为,具体的默认行为是什么呢,但它非常像click事件被带到B页面。为了验证猜测,在touchEnd方法中最后一行前添加 event.preventDefault() 

preventDefault是事件对象(Event)的一个方法,作用是取消浏览器事件的默认行为;

cancelable也是事件对象(Event)的一个方法, 表明该事件是否可以被取消默认行为,如果该事件可以用 preventDefault() 可以阻止与事件关联的默认行为,则返回 true,否则为 false

touchEnd: function (event) {this.$emit('goToDetail')if(event.cancelable) {event.preventDefault()}
}

解决方案:使用preventDefault()来阻止点透

测试发现 event.preventDefault() 能成功阻止了androids手机上vue页面切换导致事件点透的问题(目前ios并没有发现事件点透问题,可能在多个版本前修复了这个体验),也验证了猜想:div标签绑定touchend事件后,元素有了浏览器默认的行为

vue页面开发,在HTML结构上添加事件修饰符.prevent,即@touchend.prevent同样可以调用 event.preventDefault()来阻止默认行为

<template>
<divclass="item"@touchstart="touchStart"@touchmove="touchMove"@touchend.prevent="touchEnd"
><slot :data="item"></slot>
</div>
</template>

使用click作为最终事件也可以防止点透

div标签绑定touchend事件后,元素有了浏览器默认的行为,这个所谓的默认行为又触发click事件,从而引起点透的问题。

那么,如果把this.$emit('goToDetail')的方法绑定到click上,是否可以解决点透问题?

<template>
<divclass="item"@touchstart="touchStart"@touchmove="touchMove"@touchend="touchEnd"@click="click"
><slot :data="item"></slot>
</div>
</template>
click: function () {this.$emit('goToDetail')
}

 经过测试,在click事件触发this.$emit('goToDetail')方法,页面跳转成功后并不会引起点透的问题。

总结:

  • Android设备中,div等标签绑定touchend事件后,元素有了浏览器默认的行为,比如触发click
  • 移动端vue页面点透事件可以使用事件修饰符.prevent或event.preventDefault() 来阻止浏览器默认行为

最后晒上家里2只猫,祝大家圣诞快乐~ 喵

这篇关于【原】移动端vue页面点透事件 - 分析与解决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627584

相关文章

Android 12解决push framework.jar无法开机的方法小结

《Android12解决pushframework.jar无法开机的方法小结》:本文主要介绍在Android12中解决pushframework.jar无法开机的方法,包括编译指令、框架层和s... 目录1. android 编译指令1.1 framework层的编译指令1.2 替换framework.ja

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊