这里的callback就是我们在实例化这个高阶函数时传递给我们的函数,就是当用户未执行任何操作时调用的函数
import { ref, onMounted, onBeforeUnmount, Ref } from "vue";
// 节流
import { useThrottleFn } from "@vueuse/core";
/**
* 设置一个定时器,在一段时间内未操作后执行指定的回调函数,并且可以控制定时器的启动和清除。
* @param {number} interval - 未操作开始执行定时器的等待时间(秒)
* @param {number} interval2 - 执行一次的间隔时间(秒)
* @param {function} callback - 在定时器触发时执行的回调函数
* @returns {Object} 包含两个函数的对象:
* - reset: 清除定时器的函数
* - isInitTimer: 开启定时器的函数
*/
export const useUserOperation = (
interval: number = 10000,
interval2: number = 1000,
callback: () => void
): {
reset: () => void;
isInitTimer: () => void;
} => {
const countdownSeconds: Ref<number> = ref(interval / 1000);
let timeoutId: number | null = null;
let timer: NodeJS.Timer;
/**
* isOpenTimer这个参数用来判断是否可以开启定时器,因为这里用到了节流函数,
当用户在页面中有相关操作时,不断的重置定时器,而因为这里有节流函数所以函数执行会晚0.5s执行,
而当用户离开当前页面时,会先执行reset函数重置定时器,
但startInterval函数会晚0.5s执行,所以又会把定时器开启,
造成用户离开了当前页面,定时器还在执行,会造成定时器不断的调用后端接口
*/
let isOpenTimer: boolean = true;
const startTimer = (): void => {
if (!isOpenTimer) return;
countdownSeconds.value = interval / 1000;
let firstTick = true;
const tick = (): void => {
if (!firstTick) {
countdownSeconds.value -= 1;
}
if (countdownSeconds.value > 0) {
timeoutId = window.setTimeout(tick, 1000);
} else {
timeoutId = null;
timer = setInterval(() => {
callback();
}, interval2);
}
firstTick = false;
};
tick();
};
// 开启定时器执行相关操作
const startInterval = useThrottleFn(() => {
timer && clearInterval(timer);
if (timeoutId !== null) {
window.clearTimeout(timeoutId);
}
startTimer();
}, 500);
// 初始化定时器
const isInitTimer = () => {
isOpenTimer = true;
startInterval();
};
// 清除定时器
const reset = (): void => {
isOpenTimer = false;
if (timeoutId !== null) {
window.clearTimeout(timeoutId);
}
timer && clearInterval(timer);
};
onMounted(() => {
isInitTimer();
window.addEventListener("mousemove", isInitTimer);
window.addEventListener("mousedown", isInitTimer);
window.addEventListener("touchstart", isInitTimer);
window.addEventListener("touchmove", isInitTimer);
window.addEventListener("wheel", isInitTimer);
});
onBeforeUnmount(() => {
// 清除定时器
reset();
window.removeEventListener("mousemove", isInitTimer);
window.removeEventListener("mousedown", isInitTimer);
window.removeEventListener("touchstart", isInitTimer);
window.removeEventListener("touchmove", isInitTimer);
window.removeEventListener("wheel", isInitTimer);
});
// 向外抛出用户无操作时间秒数和重置方法
return {
reset,
isInitTimer
};
};