如何实现“鼠标停留在某个区域够多少毫秒才触发某个动作”


最近做到一个需求,有一个工单列表如下:

表格展示的是一个工单list,主要数据是存在一张库表里的,但是每个工单的“当前处理人”需要到其他系统中去查询,当工单比较多时比较耗时开销大。所以希望当鼠标移入到工单的状态列时实时发起请求去查询工单的当前处理人,并用浮层展示当前处理人。

大概效果如下:

代码逻辑如下:

如上这样实现功能完全没问题,但这是产生了一个不优雅的问题: 当用户无意识地快速将鼠标滑过多个工单的状态列,这时会快速发起多个工单的请求,然而这些请求其实是非必须的,造成开销浪费。

如何优化这个问题?很快就想到,只有当鼠标移入超过一定时长,才会发起请求,那么这个效果如何实现的?

很容易想到的是防抖问题,但是这个问题和防抖有所不同,防抖是在高频触发的事件中小于设定时间间隔时不执行,超过时间间隔才会执行,但最终一定会执行一次。而这个问题的是只有大于设定时长时才执行,小于设定时长不执行,有可能一次都不执行。

假设我们设定时间间隔为50ms,我们的问题可以归结为:当鼠标移入状态列并且保持在状态列里停留超过50ms才发起请求,如果在不足50ms的某个时刻鼠标移出了则不发起请求。

人的常规思路很自然会想到计时,这显然需要轮训了,当输入移入状态列时记录下移入时刻的时间戳,然后轮训的每次用当前新的时间戳减去移入时刻的时间戳,如果大于50ms则发起请求。

这样做又有新的不优雅的地方:1. 轮训又增加了新的性能开销;2. 不足50ms鼠标移出了则要清除之前的计时、清除之前的轮训任务,更糟糕的是从鼠标从一个工单的状态列移出然后又移入到另一个工单的状态列,则要重新开始计时并轮训,如果时间触发和调用如果频繁和麻烦。

上面问题是很快能想到一定会遇到的问题,显然计时并轮训的方案并不好,于是我在想有没有更好的办法呢?

稍微细想一下,移入超过50ms才执行,其实就相当于让移入的触发函数延迟执行50ms,这用setTimeout定时器就可以简单解决,剩下的问题就是不足50ms移出了,只要在移出时终止将要发生的请求即可,马上又想到可以监听鼠标移出时间onMouseLeave,在这个处理函数中清除移入时创建的定时器任务即可,这样就让将要发生的请求胎死腹中了。

如上便想到了完美的实现方案,最后看下最终的代码。

组件和HTML结构:

事件处理逻辑:


一片冰心在玉壶