【原】移动端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>
<div
class="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>
<div
class="item"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend.prevent="touchEnd"
>
<slot :data="item"></slot>
</div>
</template>
使用click作为最终事件也可以防止点透
div标签绑定touchend事件后,元素有了浏览器默认的行为,这个所谓的默认行为又触发click事件,从而引起点透的问题。
那么,如果把this.$emit('goToDetail')的方法绑定到click上,是否可以解决点透问题?
<template>
<div
class="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页面点透事件 - 分析与解决的更多相关文章
- [转载]常见的移动端H5页面开发遇到的坑和解决办法
转过来,平时看看.虽然还有很多问题至今无解.比如:华为麒麟950的P8和meta打开我们的应用首页经常偶发白屏.!! 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是 ...
- 常见的移动端H5页面开发遇到的坑和解决办法
转过来,平时看看.虽然还有很多问题至今无解.比如:华为麒麟950的P8和meta打开我们的应用首页经常偶发白屏.!! 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是 ...
- 移动端vue页面禁止移动/滚动
当需要在移动端中禁止页面滚动,加入:@touchmove.prevent即可,例子如下 <template> <div @touchmove.prevent> <h3 c ...
- vue移动端h5页面根据屏幕适配的四种方案
最近做了两个关于h5页面对接公众号的项目,不得不提打开微信浏览器内置地图导航的功能确实有点恶心.下次想起来了的话,进行总结分享一下如何处理.在vue移动端h5页面当中,其中适配是经常会遇到的问题,这块 ...
- 开发移动端web页面click事件失效问题
这两天在做一个WAP页面,在chrome上模拟移动端的时候,都好好的,然而放到手机上测试时, 发现有些点击事件直接无反应,但是有些有反应: 难道是由于我页面上有用到滚动插件,里面的touch事件的pr ...
- 关于处理移动端Vue单页面及其内嵌兼容问题
关于处理移动端Vue单页面及其内嵌兼容问题 question:由于最近转移了以前的H5项目,重构使用Vue单页面,导致部分手机内嵌或在微信浏览器中无法浏览,或者无法使用ajax请求:手机机型千变万化, ...
- (转)倾力总结40条常见的移动端Web页面问题解决方案
原文链接:戳这里 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经过研究,是devicePixelRatio作怪,因为手机分辨率太 ...
- 【转】40条常见的移动端Web页面问题解决方案
1.安卓浏览器看背景图片,有些设备会模糊 2.图片加载 3.假如手机网站不用兼容IE浏览器,一般我们会使用zep ...
- 移动端Web页面问题(转载)
1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经过研究,是devicePixelRatio作怪,因为手机分辨率太小,如果按照分辨率 ...
随机推荐
- 159.SQL注入的实现和防御措施
sql注入: 所谓sql注入,就是通过把sql命令插入到表单中或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的sql命令.具体来说,它是利用现有的应用程序,将(恶意的)sql命令注入到后台数据库 ...
- vue 中的路由为什么 采用 hash 路由模式,而不是href超链接模式(Hypertext,Reference)?
1. vue中路由模式的种类有两种 1. 一种是 hash 模式. 2. 一种是 h5 的 history 模式. 2. hash 和 history 都是来自 bom 对象 bom 来自 windo ...
- Python入门7 —— 赋值运算符补充
增量赋值 x = 10 x += 1 #就是:x = x+1 交叉赋值 a = 10 b = 20 print(a,b) temp=b # temp=20 b=a # b = 10 a=temp # ...
- cookies、sessionStorage和localStorage的异同点
相同点:都是存储于客户端 不同点: 1.存储大小 cookies数据大小不能大于4k; localStorage和sessionStroage则可以达到5M: 2.有效时间 cookies在设置的有效 ...
- 分析https网页加载http资源导致的页面报错原因及其解决方案
https网页加载http资源导致的页面报错及解决方案 https是当下的网站的主流趋势,甚至像苹果这样的大公司,则完全要求用户必须使用https地址. 然而对于以前http链接来说,我们往往就存在一 ...
- linux安装Zookeeper及redis集群
亲测有效: 1.linux下安装zookeeper:https://www.cnblogs.com/zuolun2017/p/8186254.html 2.linux下安装redis集群:https: ...
- Mybatis学习笔记——输入参数parameterType、Mybatis调用存储过程
输入参数:parameterType(两种取值符号) 1.类型为简单类型 区别: (1) #{可以为任意值} ${vaue}--->标识符只能是value (2) ...
- Maven设置阿里云镜像
<mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> & ...
- JS点击显示隐藏内容
JS点击显示隐藏密码 思路:获取元素,判断点击,如果DIV显示就隐藏,如果DIV隐藏就显示出来. 1 if(DIV是显示的){ 2 div.style.display='none'; 3 } 4 el ...
- Python爬取微博热搜以及链接
基本操作,不再详述 直接贴源码(根据当前时间创建文件): import requests from bs4 import BeautifulSoup import time def input_to_ ...