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)
}
阅读 2k
1 个回答

问题在 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 需要注册一个订阅函数
  • 在定时器的逻辑中触发 所有订阅 即可
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题