一个开源组件 bug 引发的分析
这是一个悲伤的故事。某日清晨,距离版本转测还剩一天,切图仔的我正按照计划有条不紊的画页面。当我点击一个下拉弹框组件中分页组件页数过多而出现的向后 5 页省略号时,悲剧开始了,弹框被收回了。情景再现
问题
问题的表象很简单,使用的是组件库的下拉弹窗组件,在组件中使用到了分页组件,当点击分页组件的向后 5 页快速跳转时,弹窗被收回了。我们的预期是能够继续操作的,只有点击弹框外部时,弹窗才会被收回。
分析
发现这个问题我做了如下分析:
确定这是一个问题
再次重复操作问题,确定问题出现的条件,能够在特定条件下复现的问题才是问题。我稳定的复现了问题条件是:分页组件出现向前跳转 5 页或向后跳转 5 页,点击到不会再出现向前跳转 5 页或向后跳转 5 页这样的快速跳转后,弹框会被收回。确定是自己组件配置使用问题还是组件本身 bug
我在组件的文档中并没有看到有关这个问题的特别说明。接着我又在官方提供的代码运行环境中,写了一个使用的 demo(实际项目中的代码复杂度较高,可能存在被其他样式等因素影响而产生问题,使用功能单一的 demo 有助于我们快速确定问题范围,且官方运行环境一般使用的是其最新的组件版本),发现与我在项目中使用存在同样问题。到这里可以排除是组件配置使用,组件库版本不是最新,及项目环境影响导致的问题。在组件库的开源项目中查询 issue
在 issue 中搜索关键字查询是否有相关 issue,如果运气好找到相关问题,一般会有相关的讨论,就算没有具体的解决措施也能让你明白问题大概在哪里。我运气比较差,没有找到相关问题的 issue,所以只能自己提一个 issue 了。有时间有耐心等待维护人解决你提的 issue,问题分析到这里就可以结束了。查看组件源码
显然我的时间很紧急,问题必须尽快解决,且我也想确定一下问题具体在哪里,看自己能否解决。很快我找到的相关组件的源码,经过定位发现,弹框下拉组件中使用了 v-click-outside 指令,用来触发点击指令之外的元素收起弹框。
进一步深入源码,发现 v-click-outside 组件的原理,是在 document 组件上注册了一个 click 监听事件,当有点击事件发生,监听函数会判断,点击事件发生的元素,是否包含在使用指令的元素中。如果是监听函数返回,否则触发指令绑定的事件(在弹框组件中就是隐藏弹框)。代码片段如下
// el 表示指令绑定的元素,event为点击事件
const isClickOutside = event.target !== el && !el.contains(event.target)
if (!isClickOutside) {
return
}
if (middleware(event, el)) {
handler(event, el)
}
- 断点调试
经过上面的步骤过后,我还没有发现问题的所在,所以只能打断点进行代码调试了。经过调试发现问题出在 el.contains(event.target) 这一段,分页组件中的向前 5 页元素,点击触发后就被 v-if 指令从页面中移除了。所以运行到这一句时,el 中是不包含向前 5 页元素的。也就是说这里向前 5 页元素被错误的判断为不在 el 元素中,指令绑定的弹框收起函数被触发,弹框被收回了。
解决问题
问题已经找出,现在问题是怎么解决,因为问题是出在组件中,但是我们又不能直接修改组件库代码,直接修改项目依赖代码,不利于代码维护,也治标不治本。最好是能在项目代码中添加代码解决这个问题。
开始时走了一些弯路,想着用伪元素去覆盖,被点击的元素,试图去混淆 e.target,让 el.contains(event.target) 为true。这样确实取得了一些成效,但是在页数更多了以后依然有问题,而且我也不是很清楚这样用伪元素遮挡可以让事件触发元素不是本来元素的原理是什么。更重要的一点是,写这篇文章的时候我完全回忆不出当时我为什么会想到这个方案,可能是灵感吧,解决问题真的很需要灵感。
在使用了弯路解决办法暂时解决问题后,我开始思考更彻底的解决方案。归根结底问题是出在了 v-click-outside 指令上,如果我够找到一种正确的判断方式,让被删除的元素也可以被判断为在指令注册元素中,那么问题将得到彻底解决。经过不断的尝试与思考,我发现将点击事件注册在捕获阶段触发时,得到的指令绑定元素中依然有应该被删除的点击元素。到这里问题基本就明朗了,彻底的解决方案也就出现了。
由于组件引入的 v-click-outside 指令是局部注册在下拉弹框组件上的,所以我使用了 vue 的extends 继承了组件的弹框下拉组件。在继承的组件中重新注册了指令 v-click-outside,该指令注册在 document 上的点击事件是捕获阶段触发的。
由于是继承覆盖组件库中的组件,所以组件库升级不会带来太大的影响,同时也不用重新写一个组件,减少了工作量。到这里问题就得到了彻底的解决。
输出 v-click-out 包
解决完问题之后,我在 npm 上搜索了一些 click-outside 相关的包,发现这些包中注册在 document 上的点击事件,普遍是在冒泡阶段触发的,也就是说都存在文中我所遇到的问题。于是经过几天业余时间的努力,我开源了一个基于 vue 的 click-outside 指令开源项目catch-click-outside(不要脸求star)
一点思考
在之前的工作中,我也解决了不少问题,这次之所以会记录解决过程,一个是因为这个问题我产生了一些输出,可能对别人会有些微的帮助。另一个比较重要的原因是,在解决问题过程中走了一些弯路,也遇到了一些坎,但是这些问题都在不停的思考与事件中逐渐清晰,然后被解决,我觉得这个过程很值得记录。文字功底有限,这个解决过程记录的平淡无奇,谨以此作为备忘。
转载请注明出处!
一个开源组件 bug 引发的分析的更多相关文章
- android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据
补充:关于PHP服务端可能出现的问题: 如果你刚好也像我一样,用php实现的服务端程序,采用的是apache服务器,那么虚拟主机的配置可能会影响到android应用的调试!! 在android应用中访 ...
- Android自定义控件 开源组件SlidingMenu的项目集成
在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的.关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现 ...
- .net 开源组件推荐 之 StackExchange
已经两年没更新过博客了!!! StackExchange,地址:https://github.com/StackExchange,开源的这些项目都是在StackOverflow线上使用的. 说起Sta ...
- z-index失效原因分析——由一个bug引发的对层叠上下文和z-index属性的深度思考
新年刚开工就被一个bug虐得整个人都不好了,特地记录下. (一)bug描述 在一个fixed-data-table(一个React组件)制作的表格中,需要给表头的字段提示的特效,所以做了一个提示层,但 ...
- FluentConsole是一个托管在github的C#开源组件
FluentConsole是一个托管在github的C#开源组件 阅读目录 1.控制台能有啥滑头? 2.FluentConsole基本介绍 3.使用介绍 4.资源 从该系列的第一篇文章 .NET平台开 ...
- 由一个bug引发的SQLite缓存一致性探索
问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug ...
- 开源组件ExcelReport 1.5.2 使用手册
ExcelReport是一款基于NPOI开发的报表引擎组件.它基于关注点分离的理念,将数据与样式.格式分离.让模板承载样式.格式等NPOI不怎么擅长且实现繁琐的信息,结合NPOI对数据的处理的优点将E ...
- .net 开源组件
文章转自:http://www.cnblogs.com/asxinyu/p/dotnet_opensource_project_3.html 在前2篇文章这些.NET开源项目你知道吗?让.NET开 ...
- 一个MySQL-JDBC驱动bug引起的血案……
问题背景 公司是做电商系统的,整个系统搭建在华为云上.系统设计的时候,考虑到后续的用户和订单数量比较大,需要使用一些大数据库的组件.关系型数据库这块,考虑到后续数据量的快速增长,不是直接写入MySQL ...
随机推荐
- 11 种在大多数教程中找不到的JavaScript技巧
当我开始学习JavaScript时,我把我在别人的代码.code challenge网站以及我使用的教程之外的任何地方发现的每一个节省时间的技巧都列了一个清单. 在这篇文章中,我将分享11条我认为特别 ...
- 证明xcosx无周期
假设\(xcos\,x\)有周期,依据周期函数的规律,可得 \[ \begin{aligned} xcos\,x & = (x+T)cos\,(x+T) \\ & = (x+T)cos ...
- 夯实Java基础系列19:一文搞懂Java集合类框架,以及常见面试题
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- win10安装python
下载地址:https://www.python.org/downloads/release/python-365/ 安装完成后,在cmd里输入 python ,检查是否安装成功
- .NET成人礼 | 还记得20年前一起拖过的控件吗?
本文是MVP Ediwang写的回忆一个80后的拖控件的感悟,与君共勉: 每一代人都有记忆里的味道.煤球炉.黑白电视机是属于父母的记忆.而“拖控件”式编程,启蒙了无数像我这样的80后(嗯,89也算80 ...
- 在线影视平台人人影视 v3.2.1 绿色便携版
人人影视是一款可以方便观看美剧和国外大片的视频播放软件,支持在线观看.网盘转存.离线缓存.所有客户端离线下载均加密传输,不用担心任何安全问题.全程加密的 P2P 传输,让热门资源下载更快,海外党不再惧 ...
- 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题
Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...
- display——table-cell属性
display的table和table-cell一般情况下用的不多,所以很少有人去关注它,但他们两个联手起来会给你惊喜! 当两个或者两个以上标签一起使用显示在同一行时,以前常用的是float.posi ...
- 【源码解析】自动配置的这些细节不知道,别说你会 springboot
spring-boot 相对于 spring,很重要的一个特点就是自动配置,使约定大于配置思想成功落地.xxx-spring-boot-starter 一系列引导器能够开箱即用,或者只需要很少的配置( ...
- Python flask构建微信小程序订餐系统☝☝☝
Python flask构建微信小程序订餐系统☝☝☝ 一.Flask MVC框架结构 1.1实际项目结构 1.2application.py 项目配置文件 Flask之flask-script模块使 ...