vue3计时器钩子函数,响应式失效,应该如何修改?
封装了一个处理时间的钩子函数,想用在多个地方,一个是界面头部,一个某一界面。在界面头部响应式生效了,但在另一个界面使用时却不生效,使用了watch和computed都没监听到变化:(之前我的写法是每use一次都会创建定时器,那个时候响应式是正常的。后面我觉得定时器太多了就抽出来改成一个作为常量,就有了如上问题。)
界面头部使用:
<script lang="ts" setup>
import { useTime } from "@/hooks"
const { time } = useTime()
</script>
另一界面使用:
<script lang="ts" setup>
import { ref, watch } from "vue"
import { useTime } from "@/hooks"
const { time, timeStamp } = useTime()
watch(timeStamp, () => {
console.log("timetime", timeStamp)
})
</script>
钩子函数代码如下,这应该如何解决呢?
useTime
import { onMounted, ref, computed, onBeforeUnmount } from "vue";
import { Timer , clearSysTimer} from "@/utils";
export const useTime = () => {
const WEEK = ["日", "一", "二", "三", "四", "五", "六"];
// 分割时间
const timeSpliter = (time?: string | number): Array<number> => {
const current: Date = time ? new Date(time) : new Date();
const YYYY = current.getFullYear();
const MM = current.getMonth() + 1;
const DD = current.getDate();
const hh = current.getHours();
const mm = current.getMinutes();
const ss = current.getSeconds();
const week = current.getDay();
return [YYYY, MM, DD, hh, mm, ss, week];
};
// 填充零
const zeroPadder = (value: number | string): string => {
return value > 9 ? value.toString() : "0" + value;
};
// 时间格式化
const timeFormater = (format: string, time?: string | number): string => {
const [YYYY, MM, DD, hh, mm, ss, week] = timeSpliter(time);
const result = format
.replace("YYYY", `${zeroPadder(YYYY)}`)
.replace("MM", `${zeroPadder(MM)}`)
.replace("DD", `${zeroPadder(DD)}`)
.replace("hh", `${zeroPadder(hh)}`)
.replace("mm", `${zeroPadder(mm)}`)
.replace("ss", `${zeroPadder(ss)}`)
.replace("WEEK", `星期${WEEK[week]}`);
return result;
};
// 动态
const timeStamp = ref(); // 时间戳
const time = computed(() =>timeFormater("YYYY年MM月DD日 WEEK hh:mm:ss", timeStamp.value));
const refreshTime = () => {
timeStamp.value = new Date().getTime();
};
// 自增
const timerAdder = () => {
timeStamp.value += 1000;
};
onMounted(() => {
clearSysTimer()
refreshTime();
if(!Timer.localTimer){
Timer.localTimer= setInterval(() => {
timerAdder();
}, 1000);
}
if(!Timer.sysTimer){
Timer.sysTimer= setInterval(() => {
refreshTime();
}, 1000 * 60 * 5);
}
});
onBeforeUnmount(() => {
clearSysTimer()
});
return {
timeStamp,
timeSpliter,
timeFormater,
zeroPadder,
time,
refreshTime,
};
};
@/utils/index
export const Timer:{[index:string]:any}={
sysTimer:null,
localTimer:null
}
export const clearSysTimer=()=>{
clearInterval(Timer.sysTime)
clearInterval(Timer.localTime)
}
回复
1个回答

test
2024-07-16
问题在 useTime 的这个 clearSysTimer
onMounted(() => {
clearSysTimer()
refreshTime();
if(!Timer.localTimer){
Timer.localTimer= setInterval(() => {
timerAdder();
}, 1000);
}
if(!Timer.sysTimer){
Timer.sysTimer= setInterval(() => {
refreshTime();
}, 1000 * 60 * 5);
}
});
因为 Timer.localTimer 是全局唯一的,所以当 useTime 被第二次使用时,就会把第一个 useTime 中的定时器给清掉
这里如果你是想所有地方使用 useTime 都能获取到相同的一个倒计时,那么这里通过 发布订阅 来设计是比较合适的
- useTime 只会创建一个定时器
- 使用 useTime 需要注册一个订阅函数
- 在定时器的逻辑中触发 所有订阅 即可
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容