Mindmap NextGen+DataviewJS 的文件文件夹导图树

点击在文件列表显示对应文件/文件夹。

效果 GIF,点击展开(240419 更新)

20240321_153758

20240419_173130

DataviewJS 代码
let para = dv.el(), isFile = false, folder, vs = [], r = []
const dc = str=> document.createElement(str), check = dc('input'), inpu = dc('input'), sele = dc('datalist'), dd = dc('span')
, folders = app.vault.getAllLoadedFiles().filter(p=> !p.extension).map(p=> {
  const el = dc('option'); el.value = p.path; sele.appendChild(el); return p
})
, add = p=> {
  const el = dc('span'); el.textContent = ` ${p.name||'全库'}`; el.style.cursor = 'pointer'; vs.push(p); dd.appendChild(el)
  el.ondblclick = ()=> { vs = vs.filter(item=> item !== p); el.remove(); mk(1) }
}
, tra = items=> items.map(p=> { r.push([p.path, p.name]);
  isFile ? (p.extension || tra(p.children)) : tra(p.children?.filter(p=> !p.extension))
})
dv.span(' 现在是 '); const btn = dv.el('button', '文件夹'); dv.span(' 是否多选 ')
btn.onclick = ()=> { isFile = isFile ? false : true; btn.textContent = isFile ? '文档' : '文件夹'; mk(1) }
check.type = 'checkbox'; inpu.style.width = '100px'; inpu.setAttribute('list', 'demo'); sele.id = 'demo'
inpu.onchange = ()=> { folder = folders.find(p=> p.path == inpu.value)
  if (vs.includes(folder)) { inpu.placeholder = '已选啦'; inpu.value = ''; return }; folder && mk()
}; [check, inpu, sele, dd].map(p=> dv.container.appendChild(p))
const mk = isClick=> { para.empty(); r = []; inpu.placeholder = ''
  if (check.checked) { isClick || add(folder); tra(vs) } else { dd.empty(); vs = []
    folder ? add(folder) : ['NV'].map(path=> add(app.vault.getAbstractFileByPath(path))); tra(vs)
  }; para = dv.paragraph(
    '```markmap\n---\nmarkmap:\n  height: 900\n---\n'
    + r.map(p=> `${' '.repeat((p[0].split('/').length-1)*4)}- [[${p[0]}|${p[1]}]]`).join('\n')
    + '\n```'
  ); inpu.value = ''
}; mk()
  • / 表示根目录。因此,代码中 ['/'].map(path=> 这部分代表指定默认目录为根目录。
    可根据需要自行修改为 ['文件目录']['目录1', '目录2'] 等。
  • 切换到文档层级时可能会卡,需等待。

Mindmap NextGen 插件

找到 .obsidian/plugins/obsidian-mindmap-nextgen/main.js

修改 main.js
const link = `<a href=\"${url}\">${linkText}</a>`; /* 改为
const bta = path=> app.internalPlugins.getEnabledPluginById('file-explorer').revealInFolder(app.vault.getAbstractFileByPath(path))
, link = `<button onclick="(${bta})('${linkPath}')">${linkText}</button>`

如果你有 Hover Editor 插件,也可修改 Mindmap NextGen 插件的 main.js 为下面代码:

代码
const bta = path=> { const item = app.vault.getAbstractFileByPath(path)
item.extension == 'md' ? app.plugins.plugins['obsidian-hover-editor'].spawnPopover().openFile(item)
: app.internalPlugins.getEnabledPluginById('file-explorer').revealInFolder(item)
}, link = `<button onclick="(${bta})('${linkPath}')">${linkText}</button>`

效果是点击 MD 文档出现小弹窗:image

保存 main.js,重启 Ob。

3 个赞

大佬,这种实现方式太优雅了,恰好我刚好前几天也有尝试类似的,方法比较笨重,哈哈哈:

1 个赞

一个小问题,我没改 mindmap nextgen插件的main.js代码,因为我使用的folder note,而不用左侧的文件列表,不需要点击定位到左侧文件列表

此时有一个问题,我希望点击跳转到对应的folder note,也就是说我需要的路径是AAA/BBB/BBB.md,现在只有AAA/BBB

这个代码主要想解决直接定位文件夹,它从底层不是这样构建的诶。

改了下代码,可以实现了
去掉了文件/文件夹选择,只显示文件夹树状结构,因为切换到文件太卡了
现在有两个问题,一个是查找功能,必须打全文件夹名字,而且要把dv设置里的刷新间隔调大点才好用
一个是会莫名其妙多一个分割线,不知道为什么

```dataviewjs
let para = dv.el(),
  r = [];
const el1 = dv.el("input");
el1.style.width = "100px";
dv.el("button", "查找").onclick = () => mk();
const tra = (items) =>
    items.map((p) => {
    if (p.name !== "assets" && p.name !== "待整理" && !p.extension) {
      r.push([`${p.path}/${p.name}.md`, p.name]);
        tra(p.children?.filter((p) => !p.extension));
    }}),
  mk = () => {
    para.empty();
    r = [];
    tra(
      (el1.value ? [el1.value] : ["/"]).map((path) =>
        app.vault.getAbstractFileByPath(path)
      )
    );
    para = dv.paragraph(
      "```markmap\n---\nmarkmap:\n  height: 900\n---\n" +
        r
          .map(
            (p) =>
              `${" ".repeat((p[0].split("/").length - 2) * 4)}- [[${p[0]}|${
                p[1]
              }]]`
          )
          .join("\n") +
        "\n```"
    );
  };
mk();
```
1 个赞

感觉这个更符合我的期望

如果只把原代码中的 p.path 改成这个,应该是做不出切换到文件这个功能,因为路径不对。

总之找到适合自己的就 OK。