Skip to content

运行时间统计

实现原理

页脚运行时间功能通过组合式 API 实现,具体实现流程如下:

  1. 时间计算 :基于 useRuntime 组合式函数,通过传入初始时间 2025-03-14 00:00:00 ,每秒计算当前时间与初始时间的差值,转化为天/时/分/秒格式
  2. 视图更新 :使用 prefix 配置项注入时钟图标和前缀文本,通过 innerHTML 动态更新 .runtime DOM 元素的内容
  3. 生命周期控制 :在 frontmatter 监听器中,当页面布局为首页( home )时调用 start() 启动计时器,离开时调用 stop() 清除定时器
  4. 样式集成 :通过 clockIcon SVG 图标变量实现可视化时钟效果,样式继承自 vitepress 主题变量 关键代码实现:
ts
// 页脚运行时间
const { start, stop } = useRuntime("2025-03-14 00:00:00", {
  prefix: `<span style="width: 16px; display: inline-block; vertical-align: -3px; margin-right: 3px;">${clockIcon}</span>本站已在地球上苟活了`,
});

watch(
  frontmatter,
  async (newVal) => {
    await nextTick();
    if (newVal.layout === "home") start();
    else stop();
  },
  { immediate: true }
);

新建文件

docs\.vitepress\theme\hooks目录下新建useRuntime.ts文件

ts
// 运行时间统计
import { computed, type MaybeRef, toValue } from "vue";
import { isClient } from "vitepress-theme-teek";
import { useScopeDispose } from "vitepress-theme-teek";

export interface UseRuntimeOptions {
  /**
   * 需要插入时间的元素选择器
   *
   * @default '#runtime'
   */
  selector?: string;
  /**
   * 是否立即开始
   *
   * @default false
   */
  immediate?: boolean;
  /**
   * 运行时间前缀文案
   */
  prefix?: string;
  /**
   * 运行时间后缀文案
   */
  suffix?: string;
  /**
   * 天数颜色
   *
   * @default #FFA500
   */
  dayColor?: string;
  /**
   * 小时颜色
   *
   * @default #1DBF97
   */
  hourColor?: string;
  /**
   * 分钟颜色
   *
   * @default #8A2BE2
   */
  minuteColor?: string;
  /**
   * 秒数颜色
   *
   * @default #007EC6
   */
  secondColor?: string;
}

export const useRuntime = (
  initDate: MaybeRef<string>,
  options: UseRuntimeOptions = {}
) => {
  const {
    selector = "#runtime",
    immediate = false,
    prefix = "",
    suffix = "",
    dayColor = "#FFA500",
    hourColor = "#1DBF97",
    minuteColor = "#8A2BE2",
    secondColor = "#007EC6",
  } = options;

  const startTime = computed(() => new Date(toValue(initDate)));
  let runtimeElement: HTMLElement | null;
  let timer: ReturnType<typeof setInterval> | null;

  const update = () => {
    if (!isClient || !runtimeElement) return;

    const now = new Date();
    const diff = now.getTime() - startTime.value.getTime();

    const days = Math.floor(diff / (1000 * 60 * 60 * 24));
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((diff % (1000 * 60)) / 1000);

    runtimeElement.innerHTML = `${prefix}
        <span style="color: ${dayColor}">${days}</span> 天
        <span style="color: ${hourColor}">${hours}</span> 时
        <span style="color: ${minuteColor}">${minutes}</span> 分
        <span style="color: ${secondColor}">${seconds}</span> 秒
        ${suffix}
      `;
  };

  const start = () => {
    if (!isClient) return;

    runtimeElement = document.querySelector(selector);
    if (!runtimeElement) return;

    // 初始化
    update();
    timer = setInterval(update, 1000);
  };

  const stop = () => {
    if (timer) {
      clearInterval(timer);
      timer = null;
    }
  };

  if (immediate) start();

  useScopeDispose(stop);

  return { start, stop };
};

函数注册

docs\.vitepress\theme\components\TeekLayoutProvider.vue进行注册

vue
<script setup lang="ts" name="TeekLayoutProvider">
import Teek, { clockIcon } from "vitepress-theme-teek";
import { watch, nextTick } from "vue";
import { useData } from "vitepress";
import { useRuntime } from "../hooks/useRuntime";

const { frontmatter } = useData(); // 获取 frontmatter

// 页脚运行时间
const { start, stop } = useRuntime("2025-03-14 00:00:00", {
  prefix: `<span style="width: 16px; display: inline-block; vertical-align: -3px; margin-right: 3px;">${clockIcon}</span>本站已在地球上苟活了`,
});

watch(
  frontmatter,
  async (newVal) => {
    await nextTick();
    if (newVal.layout === "home") start();
    else stop();
  },
  { immediate: true }
);
</script>

FooterInfo 配置

详情查看FooterInfo配置项:FooterInfo

FooterInfo
ts
/*  docs\.vitepress\ConfigHyde\FooterInfo.ts */

export const FooterInfo = {
  topMessage:
  bottomMessage: [
    `<span id="runtime"></span>`,
  ],
  customHtml: ``, // 搭配 ./theme/hooks/useRuntime.ts
};
最近更新