80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
|
|
// hook/useGlobalInactivity.js
|
||
|
|
import {
|
||
|
|
onMounted,
|
||
|
|
onUnmounted
|
||
|
|
} from 'vue'
|
||
|
|
|
||
|
|
export function useGlobalInactivity(callback, timeout = 60000) {
|
||
|
|
let timer = null
|
||
|
|
let isPaused = false
|
||
|
|
|
||
|
|
// ===== 高频事件节流 =====
|
||
|
|
let lastActivityTime = 0
|
||
|
|
const THROTTLE_DELAY = 300 // 300ms 内最多响应一次活动
|
||
|
|
|
||
|
|
const handleUserActivity = () => {
|
||
|
|
const now = Date.now()
|
||
|
|
if (now - lastActivityTime > THROTTLE_DELAY) {
|
||
|
|
lastActivityTime = now
|
||
|
|
resetTimer()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 低频事件(可直接绑定)
|
||
|
|
const lowFreqEvents = ['mousedown', 'click', 'keydown', 'touchstart']
|
||
|
|
// 高频事件(需节流)
|
||
|
|
const highFreqEvents = ['mousemove', 'scroll', 'wheel', 'pointermove']
|
||
|
|
|
||
|
|
const resetTimer = () => {
|
||
|
|
if (isPaused) return
|
||
|
|
if (timer) clearTimeout(timer)
|
||
|
|
timer = setTimeout(() => {
|
||
|
|
callback()
|
||
|
|
pause() // 默认触发后停止
|
||
|
|
}, timeout)
|
||
|
|
}
|
||
|
|
|
||
|
|
const pause = () => {
|
||
|
|
isPaused = true
|
||
|
|
if (timer) {
|
||
|
|
clearTimeout(timer)
|
||
|
|
timer = null
|
||
|
|
}
|
||
|
|
lowFreqEvents.forEach(e => document.removeEventListener(e, resetTimer, true))
|
||
|
|
highFreqEvents.forEach(e => document.removeEventListener(e, handleUserActivity, true))
|
||
|
|
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||
|
|
}
|
||
|
|
|
||
|
|
const resume = () => {
|
||
|
|
if (!isPaused) return
|
||
|
|
isPaused = false
|
||
|
|
resetTimer()
|
||
|
|
lowFreqEvents.forEach(e => document.addEventListener(e, resetTimer, true))
|
||
|
|
highFreqEvents.forEach(e => document.addEventListener(e, handleUserActivity, true))
|
||
|
|
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleVisibilityChange = () => {
|
||
|
|
if (document.hidden) {
|
||
|
|
pause()
|
||
|
|
} else {
|
||
|
|
resume()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const start = () => {
|
||
|
|
if (isPaused) return
|
||
|
|
resetTimer()
|
||
|
|
lowFreqEvents.forEach(e => document.addEventListener(e, resetTimer, true))
|
||
|
|
highFreqEvents.forEach(e => document.addEventListener(e, handleUserActivity, true))
|
||
|
|
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(start)
|
||
|
|
onUnmounted(pause)
|
||
|
|
|
||
|
|
return {
|
||
|
|
resume,
|
||
|
|
pause
|
||
|
|
}
|
||
|
|
}
|