感觉可以先看一下 轻量数据库 的实现方案。
基础格式和你列举的很相似:
- 二级标题
- 标题下面一行 inline property 内联属性
- 然后写链接
- 正文
用 Dataview 可以把它们提取出来并显示成一个表格。
而且不需要拆分很多个页面,单个 md 内就可以。
效果像是这样:
更新版的脚本在这里:
const useList = false;
const curNote = dv.current();
const showLink = input?.showLink ?? true;
const showImage = input?.showImage ?? true;
if (!curNote){
dv.span("当前文档未加载,请重新打开");
return;
}
let tarFile = await app.vault.getAbstractFileByPath(curNote.file.path);
// 获取当前文件的 meta 数据
const curFileMeta = app.metadataCache.getFileCache(tarFile);
const headings = curFileMeta.headings;
const headingsList = headings.map( k => k.heading )
// 获取当前文章的文本内容
const curFilePath = curNote.file.path;
const curTFile = await app.vault.getFileByPath(curFilePath)
const content = await app.vault.cachedRead(curTFile);
if (!headings) {
dv.span("当前文档缺少标题");
return;
}
const meta = content.matchAll(/#+ (.*)\n+(\[.*\:.*\])\n+(\[.*\]\(.*\))\n+(\!\[\[.*\]\])\n/gm);
// 标题作为 key,元数据作为 value,做成 DV 表格
let tableHeads = ["标题"]
// 先存成一个 dict
let metaValues = []
if (showLink) {
tableHeads.push("链接")
}
if (showImage) {
tableHeads.push("图片")
}
if (meta) {
for (let m of meta) {
let title = m[1]
// 检查 title 是否在 headings 内(避免把一些代码块内的内容也当作元数据)
if (headingsList.indexOf(title) == -1) {
continue
}
let metaList = m[2].split(" ")
let metaDict = {}
if (showImage) {
let image = m[4] ?? ""
let imageHtml = ""
if (image) {
// 把图片的displaytext 换成 📸
// image = dv.embed(image)
let imageLink = image.match(/\[\[(.*?)\]\]/)
let imageFullPath = app.metadataCache.getFirstLinkpathDest(imageLink[1], imageLink[1]).path
let resPath = app.vault.adapter.getResourcePath(imageFullPath)
imageHtml = `<img src="${resPath}" style="max-width: 300px;" />`
}
metaDict["图片"] = imageHtml
}
// 添加元数据的 key 到表头
for (let i = 0; i < metaList.length; i++) {
let keyValue = metaList[i].replace("[", "").replace("]", "").split("::")
// console.log(metaList[i], keyValue)
let key = keyValue[0].trim()
if (tableHeads.indexOf(key) == -1) {
tableHeads.push(key)
}
if (useList){
// 1. 列表形式,重复属性会合并
let value = [keyValue[1]]
metaDict[key] = metaDict[key] ? metaDict[key].concat(value) : value
} else {
// 2. 文本形式,重复属性会使用最新的
let value = keyValue[1]
metaDict[key] = metaDict[key] ? metaDict[key] + `,${value}` : value
}
}
// 添加 URL 进元数据
if (showLink) {
let url = m[3]??""
if (url) {
// 把链接的displaytext 换成 🔗
url = url.replace(/\[(.*?)\]/, "[🔗]")
}
metaDict["链接"] = url
}
let returnValuesList = []
for (let i = 0; i < tableHeads.length; i++) {
if (i == 0) {
returnValuesList.push(`[[#${m[1]}]]`)
} else {
returnValuesList.push(metaDict[tableHeads[i]] ? metaDict[tableHeads[i]] : "")
}
}
metaValues.push(returnValuesList)
}
}
dv.table(
tableHeads,
metaValues.map( k => k )
)
用法见 【Dataview 入门介绍】DV 脚本是什么?怎么用? - 经验分享 - Obsidian 中文论坛
例图里对应的文本源代码为:
### DOIO
[按键::16] [旋钮::1] [连接::蓝牙双模] [价格::378]
[DOIO 16键设计师小键盘 客制化 蓝牙双模 无线 机械键盘 KB16B-02-tmall.com天猫](https://detail.tmall.com/item.htm...)
![[250427_单手小键盘选购-img-250427_094128.webp]]
需要注意的是,列表类型的属性直接写到一起就可以,像是 [关键字::A,B]
这样。
脚本本身也有一些开关选项,可以询问 AI 进行调整。