运行时间统计
实现原理
页脚运行时间功能通过组合式 API 实现,具体实现流程如下:
- 时间计算 :基于
useRuntime
组合式函数,通过传入初始时间 2025-03-14 00:00:00 ,每秒计算当前时间与初始时间的差值,转化为天/时/分/秒格式 - 视图更新 :使用 prefix 配置项注入时钟图标和前缀文本,通过 innerHTML 动态更新 .runtime DOM 元素的内容
- 生命周期控制 :在 frontmatter 监听器中,当页面布局为首页( home )时调用 start() 启动计时器,离开时调用 stop() 清除定时器
- 样式集成 :通过 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
ts
/* docs\.vitepress\ConfigHyde\FooterInfo.ts */
export const FooterInfo = {
topMessage:
bottomMessage: [
`<span id="runtime"></span>`,
],
customHtml: ``, // 搭配 ./theme/hooks/useRuntime.ts
};