每天一个知识点
最近在给公司的一个老微信小程序项目进行维护,本人以前也没怎么接触过小程序开发,大概看了看原来的代码就上手了。
很快,一天不到,就开发了一个像模像样的页面,主要交互部分就是这个【搜索框 + 搜索按钮】,很常见的功能逻辑。
问题发现
但是,很快哈,非常快,刚上线,就被测试逮到,提了一个问题:
第一次搜索不对,第二次搜索就对了。
我心想这什么鬼啊?仔细询问了下,得知,具体复现如下:
- 点击输入框,拉起手机键盘,输入关键字,如我们输入“国务院”。
- 此时直接点击查询按钮。
- 展现的结果没有变化,还是全部文章,并没有过滤。
问题解决探索
既然知道了稳定复现步骤,我直接打开【微信开发者工具】,进行复现。
But,没有复现啊~
我一度怀疑是收集问题,因为测试用的 iPhone 手机测试的,但是谨慎的我还是先使用自己的手机再来一次测试。
很奇怪的是,在反复几次测试下,我发现我的手机(Android)也会不定的出现这个问题。
使用开发者工具的真机调试,能够看到,出现无法过滤的问题情况下接口的请求字段没有更新:
name
字段还是空的,而非我们输入的 "国务院"
基于此,我想到了是不是由于微信事件的触发顺序导致的?
一些热知识:
微信小程序原生语言下,实现数据双向绑定需要使用 事件监听 + this.setData({...})
(这一点与 React
类似)。
而我们的搜索输入框数据双向绑定事件使用了 bindblur
进行监听【这里起初是为了节约一点点性能来着】。
按钮则是使用了 bindtap
监听。
基于上述的知识,我分别在 bindblur
和 bindtap
两个监听处理函数中进行 log,最终发现果然,当错误发生时, bindtap
的log 要先于 bindblur
。
就这样,我发现了为什么过滤无效的直接原因,但目前还有一个问题——“为什么时而行时而不行?”
反复复现测试
带着这个问题,我反复进行了复现,最终被我发现了一个很有趣的现象:
如下图,当在手机键盘不手动收起的情况下,直接点击查询按钮,就必定会触发这个事件顺序触发错误的问题
而当我们手动点击收起键盘,等键盘收起后(即输入框失焦后),再点击查询按钮,则没有问题一切正常。
破案了
就这样,最终的疑惑也解决了,根本原因就在于,小程序下bindblur
和 bindtap
的事件顺序是这样的:
点击输入框外的其他控件:
先触发被点击控件的 bindtap 事件
-> 再收起键盘
-> 再触发输入框的 bindblur 事件
想要解决这个问题也很简单,我们直接将 bindblur 替换成 bindinput 在每次输入的时候都进行同步就可以了
<input bindinput="handleInput" />
<view bindtap="search">搜索</view>
发散测试
在小程序上我们发现了这个问题,那么原生的 html + js
是否也会在移动端下存在这个问题呢?
我构造了一个小demo进行测试:
PC上显然是没问题的
使用手机试一下,也没有问题,按照我们预想的先 onblur
再 onclick
触发了(即使触发onclick时,在UI上input还没失焦,但实际上 onblur 已经触发了,将数据同步了)
结论: 故此,可以得出结论,这个 blur 和 click/tap 的先后顺序问题,只有小程序上存在,H5不需要关心。而小程序请尽量使用 bindinput
来绑定 input
。