当一个元素上,同时绑定了双击事件和单击事件,当双击时,会触发单击事件,如何避免双击时触发单击事件?
方法 1:使用 setTimeout 延迟处理单击事件
通过延迟单击事件的处理时间,避免与双击事件冲突。
<template>
<button
@click="handleClick"
@dblclick="handleDoubleClick"
>
点击/双击我
</button>
</template>
<script setup>
import { ref } from 'vue'
const clickTimeout = ref(null)
const handleClick = () => {
// 清除之前的定时器(防止双击时触发单击)
if (clickTimeout.value) {
clearTimeout(clickTimeout.value)
clickTimeout.value = null
return
}
// 设置新的定时器,延迟执行单击逻辑
clickTimeout.value = setTimeout(() => {
console.log('单击事件触发')
// 执行单击逻辑...
clickTimeout.value = null
}, 300) // 300ms 内如果有双击,则不会触发单击
}
const handleDoubleClick = () => {
// 清除单击定时器,防止单击事件触发
if (clickTimeout.value) {
clearTimeout(clickTimeout.value)
clickTimeout.value = null
}
console.log('双击事件触发')
// 执行双击逻辑...
}
</script>
方法2:使用 v-click-outside 或自定义指令
如果需要在复杂交互中区分单击和双击,可以封装一个自定义指令。
实现方式:
// directives/clickOrDoubleClick.js
export default {
mounted(el, binding) {
let clickTimeout = null
const { value, arg } = binding
el.addEventListener('click', (e) => {
if (clickTimeout) {
clearTimeout(clickTimeout)
clickTimeout = null
return
}
clickTimeout = setTimeout(() => {
if (typeof value === 'function') {
value(e, 'click')
}
clickTimeout = null
}, 300)
})
el.addEventListener('dblclick', (e) => {
if (clickTimeout) {
clearTimeout(clickTimeout)
clickTimeout = null
}
if (typeof value === 'function') {
value(e, 'dblclick')
}
})
},
unmounted(el) {
el.removeEventListener('click', () => {})
el.removeEventListener('dblclick', () => {})
},
}
注册指令
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import clickOrDoubleClick from './directives/clickOrDoubleClick'
const app = createApp(App)
app.directive('click-or-double-click', clickOrDoubleClick)
app.mount('#app')
使用方式
<template>
<button
v-click-or-double-click="(e, type) => handleClick(e, type)"
>
点击/双击我
</button>
</template>
<script setup>
const handleClick = (e, type) => {
if (type === 'click') {
console.log('单击事件')
} else if (type === 'dblclick') {
console.log('双击事件')
}
}
</script>
方法 4:使用 lodash.debounce 或 lodash.throttle(适用于复杂场景)
如果单击事件逻辑较复杂,可以使用防抖(debounce)或节流(throttle)来优化。
<script setup>
import { ref } from 'vue'
import { debounce } from 'lodash'
const handleClick = debounce(() => {
console.log('单击事件(防抖处理)')
}, 300)
const handleDoubleClick = () => {
console.log('双击事件')
}
</script>
<template>
<button @click="handleClick" @dblclick="handleDoubleClick">
点击/双击我
</button>
</template>
注意
- 防抖适用于单击事件,但双击事件仍然需要单独处理。
- 如果双击事件触发后,单击事件仍然可能被误触发,建议结合 setTimeout 方法。