先记住这个答案
对同一元素的典型鼠标双击,常见序列是 mousedown → mouseup → click 两遍,然后 dblclick。浏览器不会等确认不是双击才派发第一次 click,因此“单击选中、双击打开”若在 click 里立刻执行不可逆动作,双击时也会先执行单击。要让两种操作互斥,可延迟单击动作或重新设计为兼容的交互。
- 双击包含两次单击过程
- 第二次
click后通常触发dblclick - 单击处理器不会自动延迟
- 要自行处理单击与双击冲突
文件列表单击选中、双击打开
文件管理器里单击标记选中,双击打开文件。这两种动作可以顺序共存:第一次点击先选中,第二次点击仍选中,最后打开。若单击直接删除文件,双击前就会删除,交互设计显然不合理。
const row = document.querySelector('#file-row')
row.addEventListener('click', event => {
row.classList.add('selected') // 双击时通常执行两次
console.log(event.detail) // 连续点击次数
})
row.addEventListener('dblclick', () => {
console.log('打开文件') // 典型双击的最后阶段
})MouseEvent.detail 可帮助观察连续点击次数,但业务逻辑不能只靠一个数字解决所有设备与时序问题。原生双击识别还受间隔、位置和目标等条件影响。
如果必须让单击和双击互斥,可以在单击后短暂等待并在双击到来时取消单击任务;这会给单击体验增加延迟,需要产品明确接受。
不要把时序写成绝对保证
触屏、辅助技术和脚本派发事件不一定按物理鼠标的典型序列出现。用户双击速度阈值也可能由系统设置决定,不能写死“250 毫秒内必是双击”。
实现关键功能时应给键盘用户独立入口,例如 Enter 打开文件。dblclick 可以作为快捷操作,但不宜成为唯一操作方式。
如果单击负责选中、双击负责打开,第一下选中通常不妨碍第二下打开,这种设计比用定时器“猜用户是否还会点”稳。若单击负责重命名、删除或发请求,第一次 click 已经造成副作用,等 dblclick 才回滚会很棘手;应先调整交互职责,而不是一开始就调双击阈值。
观察日志时还要确认监听目标相同。用户第一下点文字、第二下点嵌在行内的图标,事件目标及浏览器的双击识别条件可能不同。委托到父级能统一业务入口,但不能把所有两次连续点击都保证为 dblclick。
容易答错的地方
- 以为双击只触发
dblclick - 两次
click通常已经发生,单击监听器会运行。 - 把双击设为唯一打开方式
- 键盘和触屏用户可能难以触发,应提供可见或键盘可用的入口。
面试官还会怎么问?
第一次 click 能知道后面会双击吗?
不能在当下确定未来是否还会点击;需要互斥时通常等待一段时间再执行单击。
event.detail 一定等于 2 吗?
典型第二次鼠标点击常是 2,但不同输入路径或脚本事件不应机械套用。
为什么不在 mousedown 里判断双击?
按下发生在激活完成之前,且键盘没有鼠标按下路径;通常让浏览器的 dblclick 识别更合适。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。