// useHandleEvent.js
import { ref, onMounted, onUnmounted } from "vue"
interface EventType {
type: string
cell: { row: number; col: number; element: any }
originalEvent: MouseEvent | TouchEvent | any
}
export function useHandleEvent(containerRef: Ref<HTMLElement>, callback: (cb: EventType) => void) {
// 用于存储触摸开始的信息
const touchInfo: any = ref(null)
const isMobile = ref(false)
// 检测移动设备
const detectMobile = () => {
return (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)
)
}
// 用于存储最后一次点击的信息,用于区分单击和双击
const lastClickInfo = ref({
time: 0,
target: null as any
})
// 长按定时器
const longPressTimer = ref<NodeJS.Timeout | null>(null)
// 判断是否为长按
const isLongPress = ref(false)
const getCallback = (type: string, cell: any, event: any) => {
return {
type,
cell,
originalEvent: event
}
}
// 处理鼠标按下事件
const handleMouseDown = (event: MouseEvent) => {
// 如果是右键,可能是contextmenu
if (!event || event.button === 2 || event.button === 3 || isMobile.value) {
event.preventDefault() // 阻止默认的右键菜单
return
}
const cell = getCellFromEvent(event)
if (!cell) return
// 设置长按定时器
longPressTimer.value = setTimeout(() => {
isLongPress.value = true
callback(getCallback("contextmenu", cell, event))
}, 500) // 500ms后触发长按
callback(getCallback("mousedown", cell, event))
}
// 处理鼠标抬起事件
const handleMouseUp = (event: MouseEvent) => {
// 清除长按定时器
if (longPressTimer.value) {
clearTimeout(longPressTimer.value)
longPressTimer.value = null
}
// 如果是长按,不处理click事件
if (isLongPress.value) {
isLongPress.value = false
return
}
const cell = getCellFromEvent(event)
if (!cell) return
// 判断是否为双击
const now = Date.now()
if (lastClickInfo.value.target === cell && now - lastClickInfo.value.time < 300) {
// 双击
callback(getCallback("dblclick", cell, event))
// 重置最后一次点击信息
lastClickInfo.value = { time: 0, target: null }
} else {
// 单击
callback(getCallback("click", cell, event))
// 更新最后一次点击信息
lastClickInfo.value = {
time: now,
target: cell
}
}
callback(getCallback("mouseup", cell, event))
}
// 处理鼠标离开事件
const handleMouseLeave = (event: MouseEvent) => {
// 清除长按定时器
if (longPressTimer.value) {
clearTimeout(longPressTimer.value)
longPressTimer.value = null
}
isLongPress.value = false
const cell = getCellFromEvent(event)
if (!cell) return
callback(getCallback("mouseleave", cell, event))
}
// 处理右键菜单事件
const handleContextMenu = (event: MouseEvent) => {
event.preventDefault() // 阻止默认的右键菜单
const cell = getCellFromEvent(event)
if (!cell) return
callback(getCallback("contextmenu", cell, event))
}
// 处理触摸开始事件
const handleTouchStart = (event: TouchEvent) => {
console.log("handleTouchStart", event)
// 只处理单点触摸
if (event.touches.length > 1) return
const touch = event.touches[0]
const cell = getCellFromEvent(event)
if (!cell) return
// 保存触摸信息
touchInfo.value = {
startX: touch.clientX,
startY: touch.clientY,
startTime: Date.now(),
target: cell
}
// 设置长按定时器
longPressTimer.value = setTimeout(() => {
event.preventDefault() // 阻止默认的右键菜单
isLongPress.value = true
callback(getCallback("contextmenu", cell, event))
}, 500) // 500ms后触发长按
callback(getCallback("mousedown", cell, event))
}
// 处理触摸结束事件
const handleTouchEnd = (event: TouchEvent) => {
// 清除长按定时器
if (longPressTimer.value) {
clearTimeout(longPressTimer.value)
longPressTimer.value = null
}
if (!touchInfo.value) return
// 如果是长按,不处理click事件
if (isLongPress.value) {
isLongPress.value = false
touchInfo.value = null
return
}
const touch = event.changedTouches[0]
const cell = getCellFromEvent(touch)
if (!cell || cell !== touchInfo.value.target) {
touchInfo.value = null
return
}
// 判断是否为点击(触摸移动距离小于阈值)
const moveDistance = Math.sqrt(
Math.pow(touch.clientX - touchInfo.value.startX, 2) +
Math.pow(touch.clientY - touchInfo.value.startY, 2)
)
if (moveDistance < 10) {
// 移动距离小于10px认为是点击
// 判断是否为双击
const now = Date.now()
console.log("是否双击:", now - lastClickInfo.value.time, lastClickInfo.value.target, cell)
if (lastClickInfo.value.target === cell && now - lastClickInfo.value.time < 300) {
// 双击
callback(getCallback("dblclick", cell, event))
// 重置最后一次点击信息
lastClickInfo.value = { time: 0, target: null }
} else {
// 单击
callback(getCallback("click", cell, event))
// 更新最后一次点击信息
lastClickInfo.value = {
time: now,
target: cell
}
}
}
callback(getCallback("mouseup", cell, event))
touchInfo.value = null
}
// 从事件中获取单元格信息
const getCellFromEvent = (event: any) => {
if (!event) return null
// 获取事件目标
let target: any = event.target
// 如果目标不是单元格,可能是单元格内的子元素,需要向上查找
while (target && target !== containerRef.value) {
if (target.dataset && target.dataset.row !== undefined && target.dataset.col !== undefined) {
return {
row: parseInt(target.dataset.row),
col: parseInt(target.dataset.col),
element: target
}
}
target = target.parentNode
}
return null
}
// 添加事件监听器
onMounted(() => {
if (!containerRef.value) return
isMobile.value = detectMobile()
// 鼠标事件
containerRef.value.addEventListener("mousedown", handleMouseDown)
containerRef.value.addEventListener("mouseup", handleMouseUp)
containerRef.value.addEventListener("mouseleave", handleMouseLeave)
containerRef.value.addEventListener("contextmenu", handleContextMenu)
// 触摸事件
containerRef.value.addEventListener("touchstart", handleTouchStart, { passive: true })
containerRef.value.addEventListener("touchend", handleTouchEnd, { passive: true })
})
// 移除事件监听器
onUnmounted(() => {
if (!containerRef.value) return
// 鼠标事件
containerRef.value.removeEventListener("mousedown", handleMouseDown)
containerRef.value.removeEventListener("mouseup", handleMouseUp)
containerRef.value.removeEventListener("mouseleave", handleMouseLeave)
containerRef.value.removeEventListener("contextmenu", handleContextMenu)
// 触摸事件
containerRef.value.removeEventListener("touchstart", handleTouchStart)
containerRef.value.removeEventListener("touchend", handleTouchEnd)
// 清除定时器
if (longPressTimer.value) {
clearTimeout(longPressTimer.value)
}
})
return {
// 可以在这里暴露一些需要的方法或状态
}
}
请根据这段代码进行优化,在PC端和移动端统一都只返回单击click,双击dblclick和长按longclick 3种事件,其他的都阻止屏蔽