VitePress 实现短链接分享
基本逻辑
- 短链接的格式为
https://notes.linho.cc/s?q=xxxxxxxxxx
,其中q=
后面的参数是文件路径去掉.md
或者index.md
之后取 MD5 的前十位。 - 在构建阶段,生成一个 JSON 文件(
shortmap.json
)放在打包后的根目录,其中记录哈希值与路径的对应关系。 - 通过路由覆写,将
/shortUrl.md
映射到/s
,该 Markdown 文件内加载组件,请求shortmap.json
获取对应路径,并完成跳转。 - 在导航栏上注册分享组件,提供分享二维码和复制链接按钮。
构建阶段:生成哈希 - 路径对应表
生成哈希表的代码很简单:
ts
import md5 from "blueimp-md5";
import fs from "fs";
import type { SiteConfig } from "vitepress";
type ShortUrlMap = {
[key: string]: string;
};
/** 生成短链接哈希表 */
export default async function mapShortUrl(siteConfig: SiteConfig) {
const shortMap: ShortUrlMap = {};
siteConfig.pages.forEach((path) => {
path = path.replace(/(index)?\.md$/, "");
shortMap[md5(path).slice(0, 10)] = path;
});
try {
fs.writeFileSync(
`${siteConfig.outDir}/shortmap.json`,
JSON.stringify(shortMap)
);
} catch (err) {
console.error("Create shortmap.json failed!", err);
}
}
输出的 JSON 大概长这个样子:
json
{
"9f5ef1467f": "C-C++ 相关/C++ Primer/",
"6c84242693": "C-C++ 相关/C++ Primer/第1章 开始",
"41efd5a73a": "C-C++ 相关/C++ Primer/零散的笔记素材"
// ...
}
然后在 config.mts
里面的 buildEnd
钩子里面加上这个就好了:
ts
import { defineConfig } from "vitepress";
import mapShortUrl from "path/to/mapShortUrl.ts";
export default defineConfig({
// ...
buildEnd: (siteConfig) => {
mapShortUrl(siteConfig);
},
});
客户端:查表与跳转
利用 axios 请求 shortmap.json
,然后查询哈希值。如果查到了,调用 VitePress 提供的 useRouter().go
方法跳转。然后在 shortUrl.md
中引入即可。
vue
<script setup lang="ts">
import axios from "axios";
import { onMounted } from "vue";
import { useRouter } from "vitepress";
const router = useRouter();
onMounted(() => {
const id = window.location.search.match(/\?q=(.{10})$/)?.[1];
if (!id) return router.go(`./404`);
axios.get("/shortmap.json").then(
(res) =>
res.data[id] !== undefined
? router.go(`./${encodeURI(res.data[id])}`)
: router.go(`./404`),
() => router.go(`./404`)
);
});
</script>
md
---
layout: false
head:
- - meta
- name: robots
content: noindex
---
<Loading />
<ClientOnly><Jumper /></ClientOnly>
<script lang="ts" setup>
import Jumper from '/.vitepress/shortUrl/jumper.vue'
import Loading from '/.vitepress/shortUrl/loading.vue'
</script>
其中 loading.vue
是显示加载动画的组件。
客户端:分享组件
在网页上生成短链接只需要取哈希即可,不需要查表。
ts
import { useData } from "vitepress";
const { page } = useData();
const baseUrl = "https://notes.linho.cc";
const link = ref("");
watchEffect(() => {
const path = page.value.filePath.replace(/(index)?\.md$/, "");
if (encodeURI(path).length < 10)
link.value = `${baseUrl}/${encodeURI(path)}`;
else link.value = `${baseUrl}/s?q=${md5(path).slice(0, 10)}`;
});
至于展示二维码之类的细节,建议直接 看代码。
然后在 config.mts
中的 nav
中添加上该组件即可。