在前端开发中, 如果监听了DOM元素的click
事件, 且监听了dblclick
事件, 会导致某 些冲突.
冲突
如实现以下功能
- 单击
input
按钮, 设置box
元素颜色为绿色. - 双击
input
按钮, 设置box
元素颜色为红色.
以下是示例代码:
<!DOCTYPE html>
<html>
<head>
<title>click and dblclick test</title>
<meta charset="utf-8" />
</head>
<body>
<h1>click and dblclick test</h1>
<div><input type="button" value="double click here"></div>
<div id="box">color will be changed</div>
<script>
var input = document.querySelector('input'),
box = document.querySelector('#box'),
/**
* @param {String} color
*/
setBoxColor = function (color) {
console.log('setBoxColor: ' + color);
box.style.color = color;
};
input.addEventListener('click', function () {
console.log('click ' + (new Date()).getTime());
setBoxColor('green');
}, false);
input.addEventListener('dblclick', function () {
console.log('dblclick ' + (new Date()).getTime());
setBoxColor('red');
}, false);
</script>
</body>
</html>
在Chrome上运行以上代码并双击input
按钮, console会显示类似如下的结果:
click 1390545338752 click-and-dblclick-js-test.html:22
setBoxColor: green click-and-dblclick-js-test.html:18
click 1390545338895 click-and-dblclick-js-test.html:22
setBoxColor: green click-and-dblclick-js-test.html:18
dblclick 1390545338896 click-and-dblclick-js-test.html:27
setBoxColor: red click-and-dblclick-js-test.html:18
可以发现:
- 一次双击操作, 触发了两次
click
事件和一次dblclick
事件. - 第二次
click
和dblclick
事件触发几乎在同一时刻,dblclick
事件距第一次click
事件触发时间差144 ms - 在双击操作中, 连续触发的两次
click
事件, 执行了两次并不希望执行的click
事件监听器.
解决
导致双击操作中, 连续执行两次并不希望执行的click
事件监听器的根本原因是:
- 双击操作依赖两次单击操作
没有办法改变浏览器触发单/双击事件的机制, 但有办法避免在双击过程中执行两次并不 希望执行的click
事件监听器吗?
以下是解决办法:
<!DOCTYPE html>
<html>
<head>
<title>click and dblclick fix</title>
<meta charset="utf-8" />
</head>
<body>
<h1>click and dblclick fix</h1>
<div><input type="button" value="double click here"></div>
<div id="box">color will be changed</div>
<script>
var input = document.querySelector('input'),
box = document.querySelector('#box'),
/**
* @param {String} color
*/
setBoxColor = function (color) {
console.log('setBoxColor: ' + color);
box.style.color = color;
},
clickTimeout = {
_timeout: null,
/**
*
*/
set: function (fn) {
var that = this;
that.clear();
that._timeout = window.setTimeout(fn, 300);
},
clear: function () {
var that = this;
if (that._timeout) {
window.clearTimeout(that._timeout);
}
}
};
input.addEventListener('click', function () {
console.log('click ' + (new Date()).getTime());
clickTimeout.set(function () {
setBoxColor('green');
});
}, false);
input.addEventListener('dblclick', function () {
clickTimeout.clear();
console.log('dblclick ' + (new Date()).getTime());
setBoxColor('red');
}, false);
</script>
</body>
</html>
运行并双击input
按钮:
click 1390547289426 click-and-dblclick-js-fix.html:39
click 1390547289552 click-and-dblclick-js-fix.html:39
dblclick 1390547289553 click-and-dblclick-js-fix.html:47
setBoxColor: red click-and-dblclick-js-fix.html:18
在双击过程中, click
事件监听器依然会被连续执行两次, 但setBoxColor
函数不会被 click
事件监听器调用了.
缺点
以上解决方案的缺点是:
- 单击操作下的
setBoxColor
的执行开始时间比正常情况要慢300 ms