DataviewJS 的翻页与随机

从复杂到简单。前 2 帖展示效果和代码,解析已在 #4 更新,希望大家看完后都能写出自己的 DataviewJS。后续教程:DataviewJS 的传参与复用

总原理,点击展开
  • 通过 .slice 或添加新数组的方式限制一次显示的数目。
  • 通过定义函数、点击事件调用控制执行。
  • 通过全局变量 global 固定结果,通过外部 JS 保存进度。
  • 注意:使用 global 保存数据需注意变量名冲突的问题。假设你在一个 DataviewJS 使用 global.yzx 来储存,需保证 Ob 里不能本来就有 global.yzx,也不能有其他 DataviewJS 使用 global.yzx
  • 切莫不通原理随意加载外部 JS,包括本话题中的 JS。楼主不是计算机专业的,无力远程,建议坛友在阅读完本话题代码注释后,通过专业书籍确认无误再进行操作。

实例 1

  • DataviewJS
    • 检索文件目录下所有含 【****】 的块,也即含被【】和加粗包裹文本的块,每 8 个一组。
    • 点击左上角:grey_question:,若所在块有块引用,则跳转到块;无块引用,则跳转到文档。
    • 点击按钮前后翻页,点击保存记录当前进度,关闭 Ob 再次打开仍保持进度。
  • CSS
    • 将加粗内容挖空,鼠标悬停显示答案。
    • 通过指定 cssclasses,将 DataviewJS 生成的表格以卡片视图呈现。
效果

20231217_122646

内部 DataviewJS 代码:

dv.view("外部 JS 所在文件目录/dv-翻页")  // 假设外部 JS 名为"dv-翻页.js"
外部 DataviewJS 代码
async function extract(files) {
    let tdata = []
    for (let file of files) {
        let content = ( await app.vault.readRaw(file.file.path) ).split('\n\n')  // 分块
        content.filter(p=> p.includes("【**") && p.includes("**】") )  // 检索
            ?.forEach(p=> tdata.push([ `[❔](<${file.file.path}#${p.trim().match( / (\^[a-z0-9]{6,})/ )?.[1]}>)`, p.trim() ]))  // 表体格式
    }  // 翻页
    if(!global.jd) { global.jd = (localStorage.hasOwnProperty('globaljd'))
        ? Number(localStorage.getItem('globaljd')) : 0
    }; dv.el("button", "保存").onclick = ()=> { new Notice("SAVED"); localStorage.setItem('globaljd', global.jd) }
    dv.el("button", "-8").onclick = ()=> { if (global.jd > 0) global.jd -= 1; fy() }
    dv.el("button", "+8").onclick = ()=> { global.jd += 1; fy() }
    let table = dv.el('div')
    function fy() { table.empty();  // 清除旧数据
        dv.api.table( ["文件", "所在行"], tdata.slice( global.jd*8, (global.jd+1)*8 ), table, dv.component )  // 加表头成表
    }; fy()
}; extract(dv.pages(`"文件目录"`))  // 输出

注意:通过正则匹配前跟空格和 ^ 号、至少 6 位数纯数字字母组合以查找块引用 ID,若无法正确跳转,检查是否有相同匹配格式的文本干扰。

CSS 代码 - 加粗挖空
/*.fill .cm-strong:not(.cm-active > span), /*编辑模式*/
.fill strong /*阅读模式*/ {
  border-bottom: var(--size-2-1) dashed var(--color-accent); /*下划线粗细、样式、颜色*/
  text-decoration: none;
  color: transparent;
  transition: var(--anim-duration-superfast);
}
.fill .cm-strong:hover:not(.cm-active > span),
.fill strong:hover {color: var(--text-normal)}

默认要求文档 YAML 具有 cssclasses: fill,只要有就行。

CSS 代码 - 卡片视图:更新了坛里 Minimal Dataview 伪卡片 CSS

如果不知道什么是添加 CSS,此链接有详细说明:CSS 分享:自动隐藏式十字花左侧边栏

6 个赞

实例 2

效果

20231217_124318

DataviewJS 代码
let files = dv.pages(`"文件目录"`)
    .filter(p=> p.cover)
files.map(p=> p.cover = (p.file.frontmatter.cover.startsWith('http')) ? `[![|200](${p.cover})](<${p.file.path}>)`
    : `[<img width='200' src='${encodeURI(`file:${app.vault.adapter.basePath}/${p.cover.path}`)}'>](<${p.file.path}>)`)
files.length < 3 && (()=> { throw new Error('总数不足') })()
dv.el('button', '随机').onclick = ()=> { delete global.yzx; sj() }
let table = dv.el('div')
function sj() { table.empty(); let tdata = [];  // 清除旧数据
    while (tdata.length < 3) { let rdm = files[Math.floor(Math.random()*files.length)];
        if (!tdata.includes(rdm)) tdata.push(rdm)
    }; if(!global.yzx) global.yzx = tdata.map(p=> [p.cover, p.作者])  // 表体
    dv.api.table(['', '作者'], global.yzx, table, dv.component)  // 加表头成表
}; sj()  // 输出

想更改一次随机的数目,修改所有 .length < 3 的 3 为你想要的数值。注意:files.length < 3 这一行对保证 Ob 不会卡死非常重要,务必保证其后数字不小于 tdata.length 后数字。

在看懂实例 1 的前提下,可自行尝试将实例 2 的代码改为点击保存记录、关闭 Ob 再次打开仍保持。

相关:【求助】dateviewjs每天随机3本书【求助】本地图片随机封面

实例 3

  • DataviewJS
    • 随机单文件内无序列表内容,以楷体“句:内容”格式展示。
    • 点击按钮重新随机,不点击则在 Ob 关闭前一直保持随机结果。
效果

20231217_124810

DataviewJS 代码
let content = app.vault.readRaw(dv.page("文件").file.path)
content.then(p=> {
    let cList = p.split("\n")  // 分块
        .filter(p=> p.startsWith("- "))  // 检索
    function sj() { dv.container.innerHTML = '';  // 清除旧数据
        dv.el("button", "随机").onclick = ()=> { delete global.jz; sj() }
        let c = cList[Math.floor(Math.random()*cList.length)]
        if (!global.jz) global.jz = `句:${c.substring(2)}`
        dv.paragraph(`<span style="font-family: kaiti;">${global.jz}</span>`)  // 格式
    }; sj()  // 输出
})

在掌握 DataviewJS 基本插件语法的前提下,可参考实例 1 分块、检索、格式行自行尝试将实例 3 的代码改为各种路径、各种匹配格式的随机。

另,由于 Ob 保存频繁,除非你想要的刷新频率比 Ob 保存频率更快,如 2、3 秒,想要通过 JS .setInterval() 之类定时器语法定时执行意义不大。如有一定编程基础,可自行修改。
无固定结果、跟随 Ob 刷新的原始代码可参致谢 3 链接的帖子。

相关:【求助】随机展示英语单词

致谢,排名不分先后:

  1. @lazyloong Dataviewjs的奇技淫巧 #384
  2. @bedrock 文字挖空效果
  3. @xsdc 每日一句功能 #2
5 个赞

无请提供完事代码,代码在哪里?

更新简要解析,折叠三角可点击展开,没找着代码仔细重看 #1 #2
若理解困难,可依 DataviewJS 小白手册 中“小白入门 DataviewJS 方法”,先掌握基础。
额外需求仍请另建话题。点击图片或右键 - 打开图片查看大图。

  • JS 方法

    • .push() 添加新元素到数组。
    • .split() 根据指定分隔符切片字符串,每片成为新数组的每项。\n 表换行符,\n\n 表连续 2 个换行符。
    • .substring().slice() 切割。
  • Ob API:app.vault.readRaw() 读取原文。

  • 代码结构

    • dv.el("button", "按钮名").onclick = ()=> { } 生成按钮、添加点击事件。
    • Math.floor(Math.random()*数组.length) 生成随机数;数组[随机数] 取出随机项。

实例 1 要点:

实例 1 格式行
?.forEach(p=> tdata.push([ `[❔](<${file.file.path}#${p.trim().match( / (\^[a-z0-9]{6,})/ )?.[1]}>)`, p.trim() ]))

表体第一列:`[❔](<${file.file.path}#${p.trim().match( / (\^[a-z0-9]{6,})/ )?.[1]}>)`
- 格式:[❔](<文件路径#^块ID>)  // []()格式的块引用链接
- 正则:/ (\^[a-z0-9]{6,})/ )?.[1]  // ?.[1] 返回正则第一个括号捕获的内容,避免因无匹配值而抛出错误
实例 2 格式行
files.map(p=> p.cover = (p.file.frontmatter.cover.startsWith('http')) ? `[![|200](${p.cover})](<${p.file.path}>)`
    : `[<img width='200' src='${encodeURI(`${app.vault.adapter.basePath}/${p.cover.path}`)}'>](<${p.file.path}>)`)

三元运算符,判断是否以 http 开头。
- 是,格式:[![|200](图片)](<文件路径>)  // MD 格式
- 否,格式:[<img width='200' src='图片'>](<文件路径>)  // <img> 标签
2 个赞

好久不来逛论坛了,惊现JS大佬,还搭配上案例!真的贴心。

今天把这个js测试了一下,发现这个js好像会把其他js的信息清空,用这个的时候别的js会出现内容消失的情况。目测可能和清空旧数据指令有关。

经沟通,#9 所述“清空其他 JS”实际想表达的意思是,使用实例 2 时,出现和实例 2 在同一文档的其他 DataviewJS 渲染丢失。

本帖代码无法做到这点,请考虑使用 global 保存数据变量名冲突或插件冲突。