【移动端debug-3】部分安卓机型不触发touchend事件的解决方案
最近在项目中遇到一个奇怪的问题,有一个需求是这样:页面上有一个按钮,滚动页面时让它消失,停止滚动时让它显示。
常规思路:
step1、监听touchstart事件,记录Touch对象中pageY初始值startY;
step2、监听touchmove事件,记录Touch对象中pageY的变化后的值endY,当大于(endY-startY)的绝对值大于某个阈值时隐藏按钮;
step3、监听touchend事件,当触发touchend时,展现按钮
代码如下:
var startY,endY;
$("body").on("touchstart", touchStartRecord)
.on("touchmove", touchMoveHide)
.on("touchend", touchEndShow);
function touchStartRecord(event){
var touch = event.touches[0];
startY = touch.pageY;
};
function touchMoveHide(event){
var touch = event.touches[0];
endY = touch.pageY;
if (Math.abs(endY - startY) >= 5) {
//此处省略隐藏按钮的操作
}
};
function touchEndShow(event){
//此处省略重新展现按钮的操作
};
我们想得思路很清晰简洁,并且在iPhone上能顺利实现我们要的效果,但是尼玛到了安卓上,手指离开屏幕后,竟然按钮没有展现!!??WTF!
用工具调试,发现在触发touchend事件的函数里打断点,竟然进不去!!!
所以产生这一问题的原因找到了:touchend事件未被触发!
如何解决?
在stackoverflow上已经有相关话题的讨论,不少人提到,这个问题由来已久,已经给谷歌提bug了(谷歌传送门:WebView touchevents are not fired propperly if e.preventDefault() is not used on touchstart and touchmove),但是最新的安卓版本还是没修复……再次WTF!!!
在讨论中有提到如下两种解决方案:
解决方案1:
在监听touchstart或者touchmove事件的函数里,阻止事件的默认行为event.preventDefault(),那么到touchend就能正常触发。
代码如下:
var startY,endY;
$("body").on("touchstart", touchStartRecord)
.on("touchmove", touchMoveHide)
.on("touchend", touchEndShow);
function touchStartRecord(event){
var touch = event.touches[0];
startY = touch.pageY;
};
function touchMoveHide(event){
var touch = event.touches[0];
endY = touch.pageY;
if (Math.abs(endY - startY) >= 5) {
//此处省略隐藏按钮的操作
event.preventDefault();
}
};
function touchEndShow(event){
//此处省略重新展现按钮的操作
};
尼玛,滚不动了啊……由于移动端touchmove事件的默认行为就是滚动页面,我们给阻止掉了,touchend是触发了,但是不是我们想要的效果。第三次WTF!!!
国外知名插件mobiscroll的博客里有分享关于这个问题的一些处理经验:(传送门:Working with touch events)
On Android ICS if no preventDefault is called on touchstart or the first touchmove, furthertouchmove events and the touchend will not be fired. As a workaround we need to decide in the first touchmove if this is a scroll (so we don’t call preventDefault) and then manually trigger touchend。
大意是:在安卓4.0系统(即Android ICS系统),如果在touchstart和第一个touchmove触发时,没有调用preventDefault,那么后面touchmove(连续触发)以及最后的touchend都不会被触发。所以我们需要决定第一个touchmove是否是一个滚动事件(如果是,则不能preventDefault阻止默认行为)然后手动触发touchend。
解决方案2:
同时绑定touchcancel和touchend事件,这样在安卓上就能通过触发touchcancel来重新展示我们的按钮。
在touchcancel却能正常触发,而在我们的这个需求里,touchcancel的情况下,我们也是希望按钮重新展现的,那不正好就是我们想要的效果吗?
代码如下:
var startY,endY;
$("body").on("touchstart", touchStartRecord)
.on("touchmove", touchMoveHide)
.on("touchcancel touchend", touchEndShow);
function touchStartRecord(event){
var touch = event.touches[0];
startY = touch.pageY;
};
function touchMoveHide(event){
var touch = event.touches[0];
endY = touch.pageY;
if (Math.abs(endY - startY) >= 5) {
//此处省略隐藏按钮的操作
}
};
function touchEndShow(event){
//此处省略重新展现按钮的操作
};
好了,现在能够解决我们的需求了,但其实还不是最优解,因为我们如果还想给touchcancel单独增加一个操作,就不能够了。所以最根本的还是寄希望于谷歌尽早解决这个历史遗留bug。
【移动端debug-3】部分安卓机型不触发touchend事件的解决方案的更多相关文章
- 【移动端debug-4】iOS下setTimeout无法触发focus事件的解决方案
开篇总结:其实目前无法解决这个bug. 这两天做项目遇到了这个case,项目需求是打开页面的时候,input元素自动弹起键盘.由于各种方面的考虑,我们希望通过setTimeout延时200毫秒让inp ...
- 解决移动端页面滚动后不触发touchend事件
解决移动端页面滚动后不触发touchend事件 问题 在移动端页面进行优化时,一般使用touch事件替代鼠标相关事件.用的较多的是使用touchend事件替代PC端的click和mouseup事件. ...
- 移动端touchstar、touchmove、touchend 事件如果页面有滚动时不让触发 touchend 事件。
/*仅适用于内容中点击元素.对于拖动等元素,需要自行在页面处理. * 主要是绑定touchstart和touchmove事件,并判断用户按下之后手指移动了多少像素. * 如果手指移动距离小于10像素, ...
- 解决红米等手机(移动端)无法触发touchend事件
触屏事件的简单描述: js的触屏事件,主要有三个事件:touchstart,touchmove,touchend. 这三个事件最重要的属性是 pageX和 pageY,表示X坐标,Y坐标.touchs ...
- 部分安卓机型1px边框无法显示解决方法
实践发现css样式中使用1px solid 在部分安卓机型无法显示. 网上找到解决方案:使用行内样式设置边框.
- H5页面适配所有iPhone和安卓机型的六个技巧
http://www.th7.cn/web/html-css/201605/166006.shtml http://www.th7.cn/web/html-css/201601/153127.shtm ...
- 移动端开发ios和安卓兼容问题
移动端开发ios和安卓兼容问题 最近做移动端混合开的时候遇到一些安卓和iOS的兼容性问题,兼容想问题不仅在浏览器存在也在APP开发当中也会经常遇到这样的情况. 最近看了一下内容很不错的移动端开发相关的 ...
- 周记5——随机撒花特效、动态修改伪元素样式、contenteditable属性、手机端调试利器VConsole、浏览器端debug调试
记录一些小零碎知识点,以便日后查看~ 1.随机撒花特效 教师节快到了,公司的产品提出一个需求:在IM(即时聊天)聊天界面弹出教师节的祝福“广告”,用户点击“发送祝福”按钮,聊天界面会随机撒花.这里的重 ...
- h5开发安卓机型点击输入框调起输入法,输入框被键盘遮挡的解决方法
前言: 从以前的项目中找一个问题的解决方案,顺带找到了这个安卓机型调起输入法,页面没有自动上滑导致输入框被弹起的键盘遮挡的解决方案.这个问题只有安卓机型页面中的输入框处于底部(也就是底部键盘区域)的时 ...
随机推荐
- .Net 两个对像之间的映射 ( 二 )
一.使用 class Program { static void Main(string[] args) { User u1 = new User(); u1.UserName = "aaa ...
- 【commons】邮件发送工具——commons-email
一.概述 直接通过官网的overview进行了解,一句话概括如下: Commons Email aims to provide a API for sending email. It is built ...
- C#基础之委托
委托常常和事件在一起使用,可以理解委托是方法的容器,事件则是委托的另一种表现形式.委托和事件虽然写得还比较多,不过也只是用的熟练而已,趁周末没课好好巩固下基础,一点一点积累吧. 1.一个简单的小例子 ...
- 洛谷 P1941 飞扬的小鸟
洛谷 P1941 飞扬的小鸟 原题链接 首先吐槽几句 noip都快到了,我还不刷起联赛大水题! 题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节 ...
- L014-第三关课前linux命令及基础知识考试手把手实战解答小节
又是一周啊,以后保持一周一个微博吧. 这是一个堂解答考试题的课,那么就以题目来展开吧! 1.如何取得/etiantian文件的权限对应的数字内容,如-rw-r--r--为644,要求用命令获得644这 ...
- java阻塞队列之LinkedBlockingQueue
LinkedBlockingQueue是BlockingQueue中的其中一个,其实现方式为单向链表,下面看其具体实现.(均为JDK8) 一.构造函数 在LinkedBlockingQueue中有三个 ...
- ----------BMI指数小程序----------
# 1.创建并输出菜单, 菜单是不可变的. 所以使用元组# menus = ("1, 录入", "2, 查询", "3, 删除", &quo ...
- asp.net 问题:Web 服务器上的请求筛选模块被配置为 拒绝包含的查询字符串过长的请求
发现问题: post请求,在发送一个图片base64编码的字符串时,服务端报这个错误. 报错信息中给出了解决办法: 最可能的原因: Web 服务器上的请求筛选被配置为拒绝该请求,因为查询字符串过长. ...
- 【CentOS】安装Docker教程
前提条件 Docker 运行在 CentOS 7 上,要求系统为64位.系统内核版本为 3.10 以上. Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位 ...
- vue Map 渲染DOM
遍历对象(map),以键值对k:v的形式渲染DOM (1)DOM (2)数据模板