前日一群友问:双击会连带触发单击事件,想让二者独立开来,分别做不同的监听,怎么破?我随口道:对单击事件做个封装呗?问怎么封装,思考了几分钟,还真难倒了我,我是个倔强的人,再想了一会,也没找到合适的解法,就这样几星期过去了,项目又赶进度,这事不了了之,今日想起,倍感羞愧,再想想就出来了,也记录下想到的种种思路,以及种种的被推翻,聊以慰藉。
为何不用原生实现?
前文已提到: dblclick会连带触发单击事件,二者混合一起,虽然不能简单地说好坏,但有些场景的确是需要将二者独立开来的。
分析与思考
来一张分析草图

- 这个单元时间跟延时调用挺像
- 单元存在状态用一个变量保存,应该是布尔值
- 单元存在状态变化在两个时间点:单元自然结尾、单元提前结束
- 单元结束意味着 单击或双击的判定
- 判定后,需要重置相应的参数与状态
第一种写法
var unitAlive = false;
var timer = null;
function handleClick(single,double){
if(typeof single !== 'function' || typeof double !== 'function'){
throw "参数必须为函数"
}
return function(){
if(unitAlive === false){
//单元未启动阶段
//启动单元
timer = setTimeout(function(){
unitAlive = false;
single()
},160)
//更新单元存续变量
unitAlive = true;
}else{
//单元存续阶段,出现了二次点击
//提前结束单元
clearTimeout(timer);
unitAlive = false;
double()
}
}
}
//use
document.querySelector('#btn').addEventListener('click',handleClick(function(){
//单击
console.log('single')
},function(){
//双击
console.log('double')
}))
我们将单元与存续状态分为两个变量存储,因此定义了两个global变量,思考下是否能将二者合起来呢?当然可以,往下看呢:
第二种写法
将单元本身地特质决定存续状态:数组天生具备此特征,length为0则证明单元队列为空,不存在。队列为1则存在。
var unitLine = [];
function handleClick(single,double){
if(typeof single !== 'function' || typeof double !== 'function'){
throw "参数必须为函数"
}
return function(){
if(unitLine.length === 0){
//单元未启动阶段
//启动单元
line.push(setTimeout(()=>{
//清空单元队列
unitLine = [];
single();
},170))
}else if(unitLine.length === 1){
//队列种有一个
clearTimeout(unitLine[0]);//提前结束单元
unitLine = [];//清空队列
double()
}
}
}
总结
通过上述自定义地方式,实现了双击与单击的独立,当然还可以将时间间隔(单元时间长度设置为参数传入),更加灵巧。毕竟是手工实现,严格测试可能会有纰漏,正常的使用应该是没问题的,毕竟水平有限,不足之处还望读者朋友不吝赐教哦!