0%

解决问题之道

工程师最重要的不是炫技,而是解决问题。能结合最好最新的技术解决问题,才是最吼的!

上周五遇上了一个问题,浪费了一天时间,简单记录下。用的是Vue框架,所提到的所有组件均指Vue组件。

前情提要

问题产生的原因是这样的:

前一天封好的一个组件,在一个页面上已经正常了,第二天在另一个页面上再次调用却出现了问题。移动端的二级菜单,要求能左右滑动,能点击。

因为PM想要统一的效果,iOS上原生HTML/CSS拉到头就是有回弹效果的,而Android没有。(作为一只想做全沾工程师的程序猿,希望早日打通一个产品所需的全部技能栈,以更科学合理的角度和PM讨论问题,而不是跟PM说这个没问题,能做,就是麻烦点。事实上,麻烦程度可能比想象的高,关键是收益不划算,后人维护成本高破天际)

于是放弃了原生实现,改用iscroll的一个变形的库bscroll,然后因为用了别人的轮子,比较难弄明白别人到底干了什么。(事实上应该是经验不足,多看点别人的轮子的实现,再自己造几个,估计就能比较容易地看清楚他人大概的套路)

然后就是,第二个页面上组件失效了,查了一下,发现第二个页面上已经使用了iscroll库做纵向滚动,先入为主的认为了scroll库在事件方面搞了一些事情,外层元素上绑定的一些事件拦截了事件的向下传递。

然后就在这个事件上倒腾了一下午。先后把周边的同事都骚扰遍了,发现问题定位错了……

具体问题

最后定位到了真正的问题,组件用的id选择器,上一个页面只有一个这个组件,新页面用了两个这个组件,id选择器是独一无二的,重复的话,因为HTML/JS的宽容性,会选取到第一个。

而出问题的页面,第一个组件因为样式的问题一直是隐藏状态,我都忘了这个页面有两个组件这件事了。所以一直在一个看不到的组件上绑定事件,在另一个没绑上事件的组件上疯狂调试。

事实上,事件流没那么复杂,JS高程上就简单介绍了下事件捕获和事件冒泡,事件捕获从顶层document到具体的元素,事件冒泡从具体的元素一层层往上到document。

解决方案

有时我们需要用id选择器去唯一定位一个元素,但在组件中又不能用id,因为组件在一个页面多次使用会出问题。

Vue作者应该是考虑到了这个所以提供了ref,可以索引子组件,也可以直接索引元素。能在组件内部起到类似于id选择器的作用,但在全局上却不会冲突。这个东西之前没用过,感谢同事指点,同事表示,Vue嘛,就不该用命令式的语法和思路,比如document.getElement……这种。嗯,道理我也懂,只是之前没考虑过元素选择上也有这种注意事项。

其它收获

技术上的收获是在事件方面,事件的调试方法,事件的几个方法。

preventDefault方法:取消默认事件的行为,比如复选框点击后就会勾选,如果为复选框绑定点击事件,在处理该事件的方法里调该方法,可以取消这个勾选复选框的默认事件。而不是阻止事件的继续冒泡。对了,有的事件是不可以被取消的,不要无脑调用该方法……

stopPropagation方法:这个才是阻止事件冒泡/捕获的。

哦对了,怎么调试事件。打断点大家都很熟悉,但是怎么对事件打断点呢,比如有个元素上,有多个库在上面绑定了事件,那么事件触发后,是哪段JS执行了?

chrome开发者工具 - sources - 右侧面板 - Event Listener Breakpoints 里列出了所有的事件,勾选想调试的事件,比如click,再去页面上点击(触发click事件),就进入到对应的代码断点了。

我想说的

排查问题的时候最基本的方法就是控制变量,把做得绝对正确的地方都排开,问题很容易看出来。这句话说起来容易,做起来嘛……如何确定你以为正确的地方是正确的。

只能尽可能多学东西,把东西掌握得全面一点,就会更有底气去说,这里是绝对没问题的。

还有就是,版本控制非常重要,当时也是没反应过来,我有版本控制啊,我为啥怕改老代码,iscroll库全干掉试试啊。

哦对了,还要感谢同事——刚入行的应届生,不要去小公司小团队。