资讯专栏INFORMATION COLUMN

我是如何通过debug成功甩锅浏览器的:解决fixed定位元素,在页面滚动后touch事件失效问题

tulayang / 2922人阅读

摘要:二分析排查一步骤一使用搜索引擎我是在无意中发现该问题的,当时观察到的现象是绑定在上的事件有时会被触发,有时会失效。这说明并不存在偶尔失效的问题。也就是说,我需要找到确切的令响应事件失效的原因。接下来的事很简单,继续搜索事件在页面滚动后失效。

如果你关注我应该知道,我最近对PC端页面进行移动适配。在这个过程中,为了节省用户300ms的时间,同时给予用户更及时的点击反馈(这意味着更好的用户体验),我在尝试使用移动端独有的 touchstart 事件替代传统的 click 事件,这过程中我遇到了一些小问题,并成功解决了,你可以通过这篇文章查看具体的情况。

所谓祸不单行,在即将发布上线的时候,我又突然发现使用 touchstart 事件后,移动设备上出现了另一个比较诡异的现象:当用户滚动页面后,原本绑定在fixed定位的navbar元素上的 touchstart 事件会时常失效。你可以通过扫描下方二维码,并使用你的Safari浏览器或Chrome浏览器(注意:不是浏览器自带的模拟器)亲自感受这一奇怪的现象。

当然,最终我成功解决了这个问题,并且有意思的是,这个问题似乎并不出自我的代码,而被我归咎于是浏览器的Bug。但是对于这个Bug出现的原理,我也只有一个大概的推测,如果你清楚的知道产生这一现象的原因,也欢迎你和我分享。

在本篇文章中,我不但会记录我的解决方案,并且会记录我在遇到这个问题后的debug的过程与分析思路。不过如果你正被这个问题搞得焦头烂额,只想快点摆脱这个问题,你可以直接翻阅到文章底部“解决方案”部分,参考我的解决方案(我真是贴心,对吧? ?)。

一 · 问题描述

移动设备:iPhone 6

操作系统:iOS 11.2.5

测试浏览器:Safari,Chrome

点击此处查看示例代码

当在移动设备上使用测试浏览器打开网页并滚动屏幕后,会发现再次点击navbar,navbar元素绑定的 touchstart 事件并没有被触发(或偶尔不被触发)。

二 · 分析排查 (一)步骤一:使用搜索引擎

我是在无意中发现该问题的,当时观察到的现象是绑定在navbar上的 touchstart 事件有时会被触发,有时会失效。于是我使用Google搜索了“touchstart 事件偶尔失效”的关键字,很遗憾,并没有什么靠谱的答案。这说明“并不存在touchstart偶尔失效的问题”。也就是说,我需要找到确切的令 touchstart 响应事件失效的原因。

接下来,我不断的在移动设备上尝试各种操作(双击,滚动屏幕,放大等),并留心移动设备的响应,最终将 touchstart 绑定事件失效的原因确定为在“页面滚动之后”。接下来的事很简单,继续Google搜索“touchstart 事件在页面滚动后失效”。观察首屏搜索结果,并点击进去查看,遗憾的是,并没有什么合适的信息:

接着我抱着试试看的态度切换百度搜索同样的关键词,还不错,已经有了一个相似度很高的搜索结果,但是阅读后发现依然不是我想要的:

是时候上最终的大杀器了,使用英文关键字搜索!以下是我使用了“touch event doesn"t respond after page scroll”关键字的Google搜索结果:

老样子,还是没有令人满意的结果。至此我获得了两点信息:

可能是我的代码写的有问题:因为很小可能出现奇怪的现象从来没有人遇到过;

我应该从 touch 事件的相关概念上找原因;

(二)步骤二:隔离代码,明晰概念

至此,debug的第一阶段结束,我的徒劳无功表明了这个问题并不简单,我需要认真对待,接下来我采用了以下两种方法:

抽离核心代码,通过隔离外界不确定因素,排除外因;

查阅MDN上touch事件的文档,查找可能引发此类问题的内因;

思路很清晰对吧,但是我并没有在相关文档中找到可能引发此问题的任何灵感。不过好在我通过第一步已经让问题变得非常清晰了,不要灰心,继续思考。

(三)步骤三:大胆假设,小心求证

基本上到了这个阶段,debug的过程就进入到经验和直觉领域了,要成功解决这个问题,你有时还需要一点点运气,我在这个过程中尝试了以下方案:

“无脑试对”:我将在搜索引擎中看到的一些问题的解决方法,逐个试验,希望有个会管用,我可以获得更多信息去定位问题出现的原因。这些尝试有:为事件的回调函数添加 e.preventDefault() 方法,替换 touchstart 事件为 touchend 事件或者直接是 click 事件。

很尴尬,这些尝试都没有起到作用,问题依然存在,不过没有关系,我本来也没有对这个简短的尝试抱太大的期望,不过这其实也说明这个奇怪的现象和touch具体的事件类型无关,和touch事件误触发其余事件无关。

目前为止,我已经知道了 touch 事件我使用的方式是正确的,并且没有其余的因素可以干扰点击事件的触发,自然而然的,我开始好奇,浏览器到底有没有检测到我手指的“点击”。这可以通过以下代码得到答案:

window.addEventListener("touchstart", e => {
    console.log(e.target)
})

奇妙的事情发生了,我的navbar居然不再出现页面滚动后touch事件失效的问题!但是当我按照相同的思路,将代码替换为下面的代码想要看看返回值时:

var navbar = document.querySelector(".navbar")

navbar.addEventListener("touchstart", e => {
    console.log(e.target)
})

问题又出现了,并且当页面滚动后,每当我再次点击navbar,控制台没有任何输出,这意味着浏览器认为我并没有点击navbar!

这不科学,但是我已然看到胜利的曙光。当我我将原先绑定在navbar上的 touchstart 事件通过事件的冒泡机制绑定在 window 对象,通过判断 e.target 属性进行事件回调时 -- 问题解决了,页面正常了,整个世界都清净了...

最终的解决方案

代码如下:

var navbar = document.querySelector(".navbar")

window.addEventListener("touchstart", e => {
    if (e.target === navbar) {
        // callback
    }
})

扫描二维码查看正确的效果:

到此为止问题被成功解决了吗?并没有。

虽然世界清净了的那一刻令人神清气爽,但是这只是需求被实现了,问题并没有被解决,我指的是我心里的那个问题:“为什么这样就行,而原来那样就不行?”。这个问题至关重要,也希望你们不要忽略。

你同意吗?那让我们继续。

让我们再回过头分析一下我们的代码,很明显它已经非常精简了,唯一可能出问题的地方在于我们给navbar的 fixed 定位。我们再想想我们是怎么“误打误撞”解决这个问题的,navbar检测不到我们的点击,但是window可以,将这两个线索放在一起思考,我得出了一个很值得怀疑的对象:层级。

我试着取消了navbar的 position: fixed; 声明,果然,一切又都正常了。看来这一奇异现象的始作俑者就是这条声明。而我能想到与之相关的因素就是层级,我是指DOM对象的层级

最终我是这样解释这个奇怪现象产生的原因:

在页面初始化时,浏览器的DOM树被正确的渲染,也就是说DOM元素间的关系正确,因此 navbar 元素可以准确的捕捉我们的 touchstart 事件,但是当页面滚动后,浏览器丢失了 navbar 元素的层级关系, touchstart 事件无法通过冒泡被 navbar 元素捕捉,因此我们绑定的事件没有响应。而当我们让整个window对象监测 touchstart 事件后,浏览器可以重新正确的计算DOM对象间的关系,navbar 层可以捕捉到冒泡的事件,因此一切就都正常了。

这个解释有说服你吗?其实我心里也没个底,毕竟这只是我基于现象的一种推测。但无论如何,这种奇怪现象的发生,应该被归咎于浏览器,而不是我的代码(哈,松了一口气)。

到这里,这个问题就结束了吗?并没有。如果只是凭一个现象,一个推测就甩锅浏览器,会不会让人有一种钦定的感觉,让某些人不服呢?会的,我自己心就比较虚,不过没关系,只要掌握了以下的关键诀窍,甩锅浏览器还不是分分钟的事。

该诀窍就是 -- 你自己去多测几个浏览器啊,朋友!!

我们根据引擎区分不同浏览器,

使用Webkit引擎的浏览器:Chrome,Safari

使用Gecko引擎的浏览器:Firefox

使用Presto引擎的浏览器:Opera

于是我下载了Firefox浏览器重新测试了原代码下页面效果,果然没有问题!

呵呵,不是我代码的问题。都是使用Webkit引擎的浏览器不好 :)。

三 · 总结

你以为本篇文章就这么结束了?并没有(失望吧),实际上写到这里,你应该也有所感觉,虽然这次debug成功解决了问题,但整个过程并不流畅高效,并且在其中走了些许弯路。结合本次debug的经验,我总结了以下几个在下次debug过程中需要注意的方面:

依次使用Google,Google(英文关键字),百度搜索引擎搜索问题关键字;

对没有搜索到结果的问题保持警惕(检查自己的代码);

编写Demo,隔离核心代码,简化分析背景;

确保掌握相关技术知识点;

首先使用各浏览器测试(这样便可以尽早排除是否是浏览器Bug);

尽早使用 debugger 关键字而不是 console.log 方法进行调试;(没错,debugger 关键字让调试更高效);

仔细观察问题,大胆假设,小心求证;

不要放弃,在解决需求后,要解决问题;

如果有时间精力的话,将发现的问题和debug过程中学到的知识总结一篇博客吧 :);

以上,是我在实际开发过程中发现问题,分析问题并解决问题的过程和思路,希望对你们有帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/115730.html

相关文章

  • 我是如何通过debug成功甩锅览器解决fixed定位元素页面滚动touch事件失效问题

    摘要:二分析排查一步骤一使用搜索引擎我是在无意中发现该问题的,当时观察到的现象是绑定在上的事件有时会被触发,有时会失效。这说明并不存在偶尔失效的问题。也就是说,我需要找到确切的令响应事件失效的原因。接下来的事很简单,继续搜索事件在页面滚动后失效。 如果你关注我应该知道,我最近对PC端页面进行移动适配。在这个过程中,为了节省用户300ms的时间,同时给予用户更及时的点击反馈(这意味着更好的用户...

    JowayYoung 评论0 收藏0
  • H5项目常见问题汇总及解决方案

    摘要:解决方案可以解决在手机上点击事件的延迟的模块,事件也是为了解决在的延迟问题显示屏原理及设计方案说明屏是一种具备超高像素密度的液晶屏,同样大小的屏幕上显示的像素点由个变为多个,如在同样带下的屏幕上,苹果设备的显示屏中,像素点个变为个。 原文链接 - https://github.com/FrontEndRo... H5项目常见问题及注意事项 Meta基础知识: H5页面窗口自动调整到设备...

    marser 评论0 收藏0
  • H5项目常见问题及注意事项

    摘要:解决方案可以解决在手机上点击事件的延迟的模块,事件也是为了解决在的延迟问题显示屏原理及设计方案说明屏是一种具备超高像素密度的液晶屏,同样大小的屏幕上显示的像素点由个变为多个,如在同样带下的屏幕上,苹果设备的显示屏中,像素点个变为个。 Meta基础知识: H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 //一、HTML页面结构 // width 设置viewport宽度,为一...

    honhon 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<