DataviewJS 汇总全文及特定标题下内容并解决图片显示痛点

  • 不是只汇总图片,是汇总文本,且正常显示图片
  • 解决 DataviewJS 本地图片裂图痛点
  • 支持 MD、Wiki 两种链接
  • 支持最短、相对、绝对三种链接类型
  • 支持不同路径同名同后缀(但请尽量不要有类似情况)
  • 支持图片名含空格含英文括号(但请尽量不要有类似情况)
  • 保留原文图片大小
  • 图片同行可有其他内容,包括双链

非计算机专业,写了一周,希望有大佬能多多交流建议,争取能有更简洁的代码。

折叠三角可点击展开,点击图片或右键 - 打开图片查看大图。

档 1 文本
---
档: 1号
---
其他内容1
## 任务一
同行混排测试 ![|120](<同名同后缀( )含.jpg>) 同行文本 ![](文件目录/测.试.png) [引用](引用) ![[../测.试.png]]
中间内容测试。
别名测试 ![别名|140](<../其他路径/同名同后缀( )含.jpg>)
### 三级标题
1号内容
档 2 文本
---
档: 2号
---
其他内容2
## 任务一
同行混排测试 ![[同名同后缀( )含.jpg|120]] 同行文本 ![[文件目录/测.试.png]] [[引用|引用]] ![](../测.试.png)
中间内容测试。
别名测试 ![[../其他路径/同名同后缀( )含.jpg|别名|140]]
### 三级标题
2号内容
效果,左:汇总全文;右:汇总二级标题“任务一”


汇总各文档全文

要点:比对原文与文档出链元数据,从元数据中获取完整路径返还到原文。

代码
let files = dv.pages(`"文件目录"`)
let rg1 = /!\[(?!\[).*?\]\((?!<?http:|<?https:|<?file:)(.+?\.[a-zA-Z]{3,4})\>?\)|!\[\[(.+?\.[a-zA-Z]{3,4})\|?.*?\]\]/g
function extract(str) { let r = []; str.replace(rg1, (m, p1, p2)=> {r.push(p1||p2)}); return r[0] }
files.map(async p=> {
    let y = app.metadataCache.getFileCache(app.vault.getAbstractFileByPath(p.file.path)).frontmatterPosition
    let A = ( await app.vault.readRaw(p.file.path) ).split('\n')  // 分块
    if (y) A.splice(y.start.line, y.end.line-y.start.line+1)  // 去掉 YAML

    let mats = []; A.map(a=> { for (m of a.matchAll(rg1)) mats.push(m[0]) })
    let B = p.file.outlinks.filter(p=> p.embed && !/\.md$/.test(p.path))
    B.map(b=> { let path = b.path.split('/'); let dis = /.*?(?:\|)?(.*?)(?:\|)?(\d+)$/.exec(b.display);
        let src = encodeURI(`file:${app.vault.adapter.basePath}/${b.path}`);
        mats.map(m=> { let e = extract(m);
            let boo = e.replace( /\.\// ).includes('/') ? e.endsWith(path.slice(-2).join('/')) : e.endsWith(path.slice(-1))
            A = A.map(a=> a.replace(m, ()=> {
                if (boo) { return dis ? `<img width='${dis[2]}' src='${src}'>` : `<img src='${src}'>` } else { return m }
    }))})}); dv.paragraph(`##### ${p.file.link}\n${A.join('\n')}`)  // 合块、输出
})
  • JS 方法:.replace().push().map().split().splice().matchAll().filter().test().exec().includes().endsWith().slice().join()
  • Ob API:app.metadataCache.getFileCache()app.vault.getAbstractFileByPath()app.vault.readRaw()

相关:dataview怎么聚合显示全文如何自动检索文件并生成可见链接列表有没有”历史上的今天”的插件或者设置

汇总标题下内容

以汇总二级标题“任务一”为例。要点:

  • 若文档中无标题(!fc),则 return,不再进行后续步骤。
  • 截取该索引和下一索引间内容,如果该索引为最后一个,截取至末。
    对比“汇总各文档全文”可发现,其实只有截取部分不同,其余是完全一致的。
  • 虽然观念上三、四…级标题比二级标题“小”,但级数 3、4…是大于 2 的。
代码
let term = '任务一'; dv.header(2, `汇总 ${term}`)
let files = dv.pages(`"文件目录"`)
let rg1 = /!\[(?!\[).*?\]\((?!<?http:|<?https:|<?file:)(.+?\.[a-zA-Z]{3,4})\>?\)|!\[\[(.+?\.[a-zA-Z]{3,4})\|?.*?\]\]/g
function extract(str) { let r = []; str.replace(rg1, (m, p1, p2)=> {r.push(p1||p2)}); return r[0] }
files.map(async p=> {
    let fc = app.metadataCache.getFileCache(app.vault.getAbstractFileByPath(p.file.path)).headings
    if (!fc) return; let i = fc.findIndex(p=> p.level == 2 && p.heading == term)  // 获取二级且等于 term 的索引
    let j = i+1; while (fc[j]?.level > 2) j++  // fc[j]存在且级数大于二跳到下个索引
    let A = ( await app.vault.readRaw(p.file.path) ).split('\n')  // 分块
    A = fc[j] ? A.slice(fc[i].position.end.line+1, fc[j].position.end.line) : A.slice(fc[i].position.end.line+1)  // 截取

    let mats = []; A.map(a=> { for (m of a.matchAll(rg1)) mats.push(m[0]) })
    let B = p.file.outlinks.filter(p=> p.embed && !/\.md$/.test(p.path))
    B.map(b=> { let path = b.path.split('/'); let dis = /.*?(?:\|)?(.*?)(?:\|)?(\d+)$/.exec(b.display);
        let src = encodeURI(`file:${app.vault.adapter.basePath}/${b.path}`);
        mats.map(m=> { let e = extract(m);
            let boo = e.replace( /\.\// ).includes('/') ? e.endsWith(path.slice(-2).join('/')) : e.endsWith(path.slice(-1))
            A = A.map(a=> a.replace(m, ()=> {
                if (boo) { return dis ? `<img width='${dis[2]}' src='${src}'>` : `<img src='${src}'>` } else { return m }
    }))})}); dv.paragraph(`##### ${p.file.link}\n${A.join('\n')}`)  // 合块、输出
})

当然,你可以通过不同的条件判断自由选择截取范围。
你也可以在 .findIndex() 中用 .startsWith().includes() 等多种方法,选择以特定字符开头或包含特定字符的标题下内容,等等。

相关:dataview图片显示问题怎么在dataview生成的表格里添加正文指定标题里的内容?Dataviewjs的奇技淫巧 #115

  • 注意:连续纯图指图片间无其他内容,包括仅有换行符的情况。
    为省空间,默认连续纯图并排显示,可自行修改代码或配合其他方式自行调整。
  • 代码中的 rg1 在 MD 和 Wiki 格式基础上匹配中间或末尾 . + 3~4 个英文字符,若遇其他形式的后缀可自行更改。

遇任何问题,请使用最新代码,先电脑端使用本话题提供的示例档沙箱测试(图片换成自己的),尝试刷新代码块或重启 Ob。错误报告请参 论坛发帖指导2023“求助反馈不重不漏自查表”,提供必要信息。

本话题主要提供方法,表格输出可参 #3,其余不一一列举。若理解困难,可依 DataviewJS 小白手册 中“小白入门 DataviewJS 方法”,先掌握基础。额外需求仍请另建话题。

了解更多:

5 个赞

感谢lz详细的说明和测试,完美解决图片显示!
但在尝试过中,我似乎有几个问题和困惑

1.在渲染的编辑模式下可以正常显示,但不知为何在阅读模式会报错?
20240107024936788

2.目前渲染的结果是排列方式如下:
文件
内容
文件
内容

请问能否以list或者table的形式呈现?即:
文件 内容
文件 内容
文件 内容

1、

请问排查步骤做了吗?沙箱结果是什么?请参论坛发帖指导2023“求助反馈不重不漏自查表”,提供必要信息。

2、

本话题主要提供如何显示图片,有了方法,其他展现形式都是基本用法,没有限制的。

要点:

image

注意:要点作修改点拨,不代表要点没提到的代码可以删除。

效果

提醒:JS 负责生成元素,一般诸如表格间距过大、表格内容行距过大、表格内容有的换行有的不换行等空白字符和换行显示问题(CSS white-space 属性),等问题,可能需要排查主题或 CSS,而非 DataviewJS。

纯小白问下大佬,为啥如下图的不能显示图片。
代码是您的代码,我就改了个路径

我记得,我没加.test的时候也不行。在中间加.test是想和您的测试案例保持一致

牛皮呀。大佬,如图可以显示了

大佬这个代码可以在加个以标签(#2024年/第02周)为条件筛选么
现在的笔记格式如下:

二级标题1

  • 标签:#2024年/第02周 #其他标签1

三级标题1

  • 内容1
  • 内容2

二级标题2

  • 标签:#2023年/第51周 #其他标签2

三级标题2

  • 内容1
  • 内容2

从上面类似的md比较内容里,筛选出下面的内容

二级标题1

  • 标签:#2024年/第02周 #其他标签1

三级标题1

  • 内容1
  • 内容2

你仍可以通过论坛正常发帖流程,在“疑问解答”类别求助。

好嘞 谢谢大佬指导。 我自己先摸索下