如何锁定某一个文件对象?

使用dataview可以通过文件名等方式,得到某个文件内的全部任务。
我希望实现类似这样的效果:

右边的文件是没有切换的,可以跟随编辑文件的变化而变化显示文件内的任务情况,可以做到么?

没找到特别直观的实现方式, 我目前卡在 “怎么让侧栏某个 dv 块, 在主栏的某个标签页改变后, 就自动重新计算一次” 这事 (能实现, 但不知道怎么弄简单点)

我目前想到几个办法, 从简单到复杂:

A 如果目标就是让侧栏同步显示主栏笔记的待办任务

那其实可以不管 dataview, 许多插件已经做了类似的事
例如 ivan-lednev/obsidian-day-planner 可以把当前笔记的待办直接列出来到侧栏 (该插件主要目标是给带 HH:mm 格式的任务排个可视化时间轴, 但也可以列出当前笔记所有无时间戳的任务)


B 如果目标是让侧栏笔记作为主栏的伴侣笔记, 一定要以 dataview 去汇总主栏的某些信息

做到下面几件事就行

  1. dv 块写成动态获取当前活动文件的路径, 据此做任务汇总
  2. 在笔记页面变化后, 刷新所有的 dv 块 (适合 “dv 全局刷新” 的开销可接受时, 即仓库总笔记不多时)
// 以下是侧栏辅助笔记的 dataviewjs
const activePage = app.workspace.getActiveFile();
if (activePage) {
	const currentFile = dv.page(activePage.path).file;
	if (currentFile.tasks.length) {
		dv.paragraph(`Find ${currentFile.tasks.length} Task(s) on ${activePage.basename}`);
		dv.taskList(currentFile.tasks, false);
	} else {
		dv.paragraph(`(No Tasks on Page ${activePage.path})`);
	}
} else {
    dv.paragraph("(No active page)");
}

然后在标签页变动时, 设法触发一次 dv 块的刷新

// 以下在 console 里执行一下, 或利用任何带运行脚本功能的插件
// 于是此后每当 'active-leaf-change' 发生时, 就执行 dv 刷新
// 参考 https://forum-zh.obsidian.md/t/topic/25760/35
app.workspace.onLayoutReady(() => {
    let stTimer;
    app.workspace.on('active-leaf-change', async (activeLeaf) => {
        // 定时防止无效触发,只取最后一个触发
        if(stTimer) clearTimeout(stTimer);
        stTimer = setTimeout(() => {
            new Notice('将要执行 dataview refresh');
            app.commands.executeCommandById("dataview:dataview-force-refresh-views");
        }, 500)
    })
})

若不需频繁使用, 直接在 Ob 命令行手动执行 “Dataview Force Refresh” 也行


C 跟方案 B 类似的另一个办法, 当标签页变更后, 向侧栏笔记写入信息

  1. dv 块从固定位置的参数读取一个笔记路径, 然后就始终汇总该笔记里的待办
  2. 在标签页变化后, 向该固定位置写入新的笔记路径
// 以下是侧栏辅助笔记的 dataviewjs
// 在侧栏笔记里写一个文档属性, 假设叫 note_path_for_task_sum
// ---
// note_path_for_task_sum: xxx.md
// --- 

// 侧栏 dv 块始终汇总该 note_path_for_task_sum 路径内的待办
const page = dv.page(dv.current().file.frontmatter.note_path_for_task_sum);
if (page) {
	const currentFile = page.file;
        // 以下都跟 方案 B 一样...... 

然后在标签页变化后, 向侧栏笔记的 YFM 里写下指定属性
可以考虑用 processFrontMatter, 我从这里学来的 快速操作笔记的元数据,汇总近期完成事项 - 经验分享

// 参考 方案 B, 以下在 console 里执行一下, 或利用任何带运行脚本功能的插件
app.workspace.onLayoutReady(() => {
    let stTimer;
    app.workspace.on('active-leaf-change', async (activeLeaf) => {
        if(stTimer) clearTimeout(stTimer);
        stTimer = setTimeout(() => {
            const activePage = app.workspace.getActiveFile();
            const sidebarNotePath = "path/to/侧栏笔记.md";
            const fileObj = app.vault.getAbstractFileByPath(sidebarNotePath);
            app.fileManager.processFrontMatter(fileObj, fm => { 
                fm["note_path_for_task_sum"] = activePage.path;
                new Notice(`YFM update note_path_for_task_sum => ${activePage.path}`);
            })
        }, 500)
    })
})

方案 C 一旦侧栏笔记的内容被修改, dv 就会自动重算, 于是省了强制 dv 刷新那一步, 这办法的优势在于可控性更好, 比如甚至可以实现: 在侧栏汇总 “最近N个访问过的文件” 里的待办任务

1 个赞

非常感谢大佬,不用dataview其实也行,只是没想到可以用day planner来做。

看到这个想起来,像是 QuiterOutline ( github.com/guopenghui/obsidian-quiet-outline )这类插件都是在侧栏的同时,可以实时显示 当前激活文件 的数据的,或许也可以参考一下它们的实现原理?