问题
如果给一个jquery获取的对象同时绑定单击和双击事件,那么在触发双击事件的同时必定会触发两次单击事件。(如下图所示)
<body>
<button>点击</button>
<script src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script>
$('button').click(function () { console.log('单击') });
$('button').dblclick(function () { console.log('双击') });
</script>
</body>
以下分别是单击和双击时控制台打印的结果
’
解决思路
第一步:在单击事件里设置一个定时器来执行事件内容,并且在每次单击事件执行的第一步清除定时器(类似节流的写法)。这一步保证在双击的时候第一次单击的内容不会被执行。
第二步:在双击事件的第一步清除定时器,这样就保证了第二次单击内容也不会被执行,而只有双击事件执行。
代码实现:
<body>
<button>点击</button>
<script src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script>
var timeout
$('button').click(() => {
// 清除之前的定时器
clearTimeout(timeout);
timeout = setTimeout(() => {
// 执行单击内容
console.log('单击');
}, 200)
});
$('button').dblclick(() => {
clearTimeout(timeout);
console.log('双击');
});
</script>
</body>
以下为双击时控制台打印的结果
详解以及注意事项
接下来结合上面的例子对原理进行更进一步说明
当执行单击事件时,此时第一次单击事件会生成一个定时器,姑且称为定时器1。(如下图)
当在等待时间内再次点击触发点击事件。此时触发第二次单击事件和一次双击事件。(如下图)由最初未进行处理的代码打印结果(2个单击+1个双击)可知执行顺序是先单击后双击。所以会先执行第二次单击事件,同时清除定时器1,并生成定时器2。之后出发触发双击事件,清除定时器2。
因此,“单击”不会再打印,而只有“双击”打印。
但如果两次单击事件的间隔超过了定时器的等待时长会发生什么?(如下图所示)在第二次单击时,第一次定时器已经结束了等待,也就是说第二次单击事件中清空的定时器1是已经执行完了的。之后触发第一次双击事件,清除定时器2。最终结果就是“单击”打印了1次,“双击”打印了1次
潜在的问题
所以综上所述,为了确保定时器1能被清除,需要在保证定时器的等待时间足够长(200ms是一个接近临界的选择),但这也意味着单击事件的执行会有一个基于定时器的延迟。在某些对延迟要求高的场合下,本文提供的方法未必是一个优解。