如何快速统计并汇总子页面的链接
以前用 Notion 的时候,留下一个习惯:
把子级页面都集中放在父级页面中。
在 Obsidian 这边,基本上就是:把同文件夹里的其他笔记的链接都汇总起来。
(配合 FolderNotes 插件可以获得相当好的嵌套笔记体验)
为了便于排查尚未链接的笔记,写了这个 DV 脚本,可以直接呈现出当前文件夹内还没链接的子笔记:
提供了链接格式和纯文本两种格式:
- 上半部分的链接可以用鼠标拖动直接放进笔记里
- 纯文本则可以用右上角的复制按钮来批量复制,适合笔记数量较多的情况
DV 脚本
关于使用的说明,可以看这篇指导:【占位符,还没发布】
```dataviewjs
// 统计当前笔记所在的文件夹下,有哪些笔记还没出现在当前笔记内
// 可以通过修改 folderDepth 参数来设置搜索的目录层级
const input = {};
// 设置参数
const folderDepth = 1; // 设置搜索的目录层级,1表示只搜索当前目录,2表示搜索当前目录及其子目录,以此类推
const ignoreRules = input?.ignore || []; // 忽略规则,可以是正则表达式或字符串
// 获取当前文件
const currentFile = dv.current();
// 获取当前文件的路径
const currentFilePath = currentFile.file.path;
// 获取当前文件所在的文件夹路径
const folderPath = currentFilePath.substring(0, currentFilePath.lastIndexOf('/'));
// 如果路径中没有'/',说明文件在根目录下
const currentFolder = folderPath === currentFilePath ? '' : folderPath;
// 获取当前文件的内容
const content = await dv.io.load(currentFilePath);
// 获取指定文件夹下的所有笔记
let notesInFolder = [];
if (folderDepth === 1) {
// 只搜索当前目录
notesInFolder = dv.pages()
.where(p => p.file.path.startsWith(currentFolder) &&
p.file.path !== currentFilePath &&
p.file.path.substring(currentFolder.length + 1).indexOf('/') === -1);
} else {
// 搜索多级目录
notesInFolder = dv.pages()
.where(p => {
if (!p.file.path.startsWith(currentFolder) || p.file.path === currentFilePath) {
return false;
}
// 计算路径中的目录层级
const relativePath = p.file.path.substring(currentFolder.length + 1);
const slashCount = (relativePath.match(/\//g) || []).length;
return slashCount < folderDepth;
});
}
// 应用忽略规则,过滤掉需要忽略的笔记
let ignoredCount = 0;
const filteredNotes = notesInFolder.filter(note => {
// 检查是否符合忽略规则
for (const rule of ignoreRules) {
if (rule instanceof RegExp) {
// 正则表达式规则
if (rule.test(note.file.name) || rule.test(note.file.path)) {
ignoredCount++;
return false;
}
} else if (typeof rule === 'string') {
// 字符串规则
if (note.file.name.includes(rule) || note.file.path.includes(rule)) {
ignoredCount++;
return false;
}
}
}
return true;
});
// 检查每个笔记是否在当前文件中被引用
const unreferencedNotes = filteredNotes.filter(note => {
// 构建链接格式,检查是否在内容中出现
const linkFormats = [
`[[${note.file.name}]]`, // 标准链接格式
`undefined`, // 嵌入格式
`[[${note.file.path}]]`, // 完整路径链接格式
`undefined`, // 完整路径嵌入格式
new RegExp( `\\[\\[${escapeRegExp(note.file.name)}\\|.*?\\]\\]` ), // 带别名的链接格式 [[文件名|别名]]
new RegExp( `\\[\\[${escapeRegExp(note.file.path)}\\|.*?\\]\\]` ) // 带别名的完整路径链接格式 [[路径|别名]]
];
// 如果笔记有别名,也检查别名链接
if (note.aliases) {
note.aliases.forEach(alias => {
linkFormats.push( `[[${alias}]]` );
linkFormats.push( `undefined` );
});
}
// 检查所有可能的链接格式
return !linkFormats.some(format => {
if (format instanceof RegExp) {
return format.test(content);
}
return content.includes(format);
});
});
// 用于转义正则表达式中的特殊字符
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& 表示整个匹配的字符串
}
// 显示结果
if (unreferencedNotes.length > 0) {
// dv.header(3, "未引用的笔记列表");
dv.paragraph(`共计 ${unreferencedNotes.length} 个未引用的笔记${ignoredCount > 0 ? ` *(${ignoredCount} 个笔记被忽略规则过滤)*` : ''}`)
dv.paragraph("#### 链接格式")
dv.paragraph(
unreferencedNotes.map(note =>
dv.fileLink(note.file.path, false, note.file.name)
)
);
dv.paragraph("\n#### 纯文本")
// 拼接成一个纯文本,包在 > 中
const pureText = "```txt\n" + unreferencedNotes.map(note => `[[${note.file.name}]]`).join('\n') + "\n```";
dv.paragraph(pureText);
} else {
dv.paragraph(`✅ 所有笔记都已被引用${ignoredCount > 0 ? `,${ignoredCount} 个笔记被忽略规则过滤` : ''}`);
}
```
单独的脚本文件:showUnlinkedSubNotes.js · GitHub
过滤笔记
有时候不是所有的笔记都想要链接,这个时候可以用下面这样的方式来过滤:
```dataviewjs
dv.view("showUnlinkedSubNotes", {ignore: [/2[34]\d{4}.*/, "特定文本"]})
```
ignore: []
是个列表,把需要忽略的文本或者正则表达式放进去即可。
讨论
若阁下有独到的见解或新颖的想法,诚邀您在文章下方留言,与大家共同探讨。
反馈交流
其他渠道
版权声明
版权声明:所有 PKMer 文章如果需要转载,请附上原文出处链接。