前文
说实话第一眼看到这个bug一脸懵逼
排查超两个小时之久
发现竟然如此简单
才惊呼一声
卧槽
问题
今天有网友反馈,在这里点击按钮触发输入框会无效
但是如果在控制台执行代码就是有效的
代码也很简单
// 创造事件
var event1 = document.createEvent('HTMLEvents');
event1.initEvent("input", true, true);
event1.eventType = 'message';
// 调度事件
inpEle.dispatchEvent(event1);
首先来猜测一下
可能是
猜想一:控制台与JS代码执行环境不一致导致的?
尝试初始化出来一个函数
然后使用settimeout执行,发现依然可以正常执行
换到网页按钮点击却不好使了
猜想二:会不会因为API老旧出现的一些问题
尝试改造成new Event依然无果
猜想三:未初始化赋值?
尝试打印vue属性后,输出value发现成功赋值,未解决
猜想四:会不会Event的值在控制台与js生成不一致导致的
尝试打印了一下发现没任何区别...
那问题到底在哪?
心机之蛙一直摸你肚子!
开始分析
找到对应的列表dom,发现他根据
对应的display的none和没有display来隐藏和展示列表
我们直接打个dom的属性断点
发现断点堆栈的层级还是比较深的
我一开始以为路径不对,于是开个一个窗口卡住,另一个按二分法做堆栈的比对
发现基本每一个函数都执行到了
那到底是什么问题呢?
每个函数都执行到了
一个显示一个却没有显示
我们开始寻找到底哪里设置了display
逐步停在各种的属性修改代码
最后找到了
这里
这里通过e.__vOriginaDisplay来控制显示和隐藏
这个时候我们触发一次控制台的执行
这个函数会经过多次调用
每次display的结果分别是
none
none
无
无
....
然后再触发一次按钮的调用
可以发现display的结果分别是
none
none
无
无
none
none
none
.........
那到底为什么又出现了none?
我们可以确定触发输入改变而出现的搜索框是有正常从none变成无的
但是为什么又从无变成none了?
那我们可以推测出来一个大胆的想法
1.首先我们点击按钮
2.按钮触发event
3.触发列表的显示
4.按钮的事件向上传递
5.传递到某个监听点击的dom,dom又取消了列表的显示
因为在控制台上不会触发点击
所以自然不存在列表再次隐藏的问题
那我们可以测试一下
直接在油猴里Settimeout一个20秒之后回调函数
发现结果跟控制台一致
那问题就很好解决了
解决方案
1.在button包裹一个div,并且在监听到相应事件的时候进行一次阻断事件
2.使用代码进行操控,不绘制按钮
3.利用html兼容特性
一般的代码只会监听body一级或子级
而即使插入多个body也可以正常显示,但是不在监听范围内
结语
本质就是一个时序问题
没想到表现出来的特征这么微妙...