Obsidian 插件篇 -DataviewJS 参考示例

在上文 Obsidian插件篇-DataviewJS基础知识 的基础上,本篇文章主要提供一些验证后的 DataviewJS 脚本供大家学习并仿写实践。

以下 DataviewJS 脚本,可以直接复制使用,标题即是脚本实现的功能。

生成当前文件目录(文本形式)

const startHeadingLevel = 0 // 起始标题级别
const file = app.workspace.getActiveFile()
const { headings } = app.metadataCache.getFileCache(file)
const lists = headings.map(p=>
  `${' '.repeat((p.level - startHeadingLevel) * 4)}- ${p.heading}`
) // 前导空格 + 列表格式
dv.paragraph(lists.join('\n')) // 输出

生成指定文件夹位置下所有子文件目录

dataviewjs
const dFiles = dv.pages(`"0.Atlas"`)
const startHeadingLevel = 0
dFiles.map(async dFile=> {
  const file = app.vault.getAbstractFileByPath(dFile.file.path)
  const { headings } = app.metadataCache.getFileCache(file)
  const lists = headings.filter(p=> p).map(p=>
    `${' '.repeat((p.level - startHeadingLevel) * 4)}- ${p.heading}`
  )
  dv.header(6, dFile.file.link)
  dv.paragraph(lists.join('\n'))
})

根据标题生成点击可跳转的目录

原文见:使用DV创建动态更新的笔记目录大纲(TOC) - 经验分享 - Obsidian 中文论坛

dataviewjs
dv.header(2,"目录");
// 标题级别,按需修改
const startHeadinglevel = 2;
const file = app.workspace.getActiveFile();
const { headings } = app.metadataCache.getFileCache(file);

// 全列表的形式
const raws = headings.map( p => {
    let repeatCount = Math.max((p.level - startHeadinglevel) * 4, 0);
    let spacesPrefix = ' '.repeat( repeatCount + 4 );
    let listSign = repeatCount > 0 ? '- ' : '';
    let linkText = `[[#${p.heading}]]`;
    let headingList = (p.level < startHeadinglevel) ? `- ${linkText}` : `${spacesPrefix}- ${linkText}`;
    return headingList;
  }
)

let result = raws.join('\n');
// 添加行距
dv.container.style.lineHeight = "1.5em";
dv.paragraph(result)
dataviewjs
// 一级列表单独显示的形式
// 标题级别,按需修改
const startHeadinglevel = 2;
const file = app.workspace.getActiveFile();
const { headings } = app.metadataCache.getFileCache(file);

let output = '';
const additionalAttr = {attr: {style: 'margin-block-start: 0 !important; margin-block-end: 0 !important;'}};

// 整个 dv 容器的样式调整
dv.container.style.marginBlockStart = "0em";

headings.forEach ( h => {
    if (h.level < startHeadinglevel) {
        // 先输出之前的子列表内容
        if (output) dv.paragraph(output, additionalAttr);

        // 将一级标题输出成单独的段落
        output = `[[#${h.heading}]]\n`;
        dv.paragraph(output);
        output = '';
    } else {
        output += `${' '.repeat((h.level - startHeadinglevel) * 4)}- #${h.heading}\n`;
    }
})

// 把最后的残余内容输出出来
if (output) dv.paragraph(output, additionalAttr);

按钮修改 yaml

dataviewjs
// 这个是按钮的点击函数
const {update,autoprop} = this.app.plugins.plugins["metaedit"].api;

const buttonMaker = (pn, pv, fpath) => {
	//  选项,值,路径
    const btn = this.container.createEl('button', {"text": pv});
    btn.addEventListener('click', async (evt) => {
        evt.preventDefault();
        //"新内容"要在Auto Properties中事先配置
		const newtext = await autoprop("新内容")
        await update(pn, newtext, fpath);
    });
    return btn;
}

dv.table(["文件","路径", "tags", "status"],
	dv.pages("#Linux")
	.map(t=>[t.file.link, t.file.folder,buttonMaker('tags',t.tags,t.file.path), buttonMaker('status', t.status, t.file.path)])
)

所有标签列表

dataviewjs
// 生成所有的标签且形成列表
dv.list(dv.pages("").file.tags.distinct())
dataviewjs
// 生成所有的标签且以 | 分割,修改时只需要修改 join(" | ") 里面的内容。
dv.paragraph(
  dv.pages("").file.tags.distinct().map(t => {return `[${t}](${t})`}).array().join(" | ")
)
dataviewjs
// 基于文件夹聚类所有的标签。
for (let group of dv.pages("").filter(p => p.file.folder != "").groupBy(p => p.file.folder.split("/")[0])) {
  dv.paragraph(`### ${group.key}`);
  dv.paragraph(
    dv.pages(`"${group.key}"`).file.tags.distinct().map(t => {return `[${t}](${t})`}).array().sort().join(" | "));
}

未设置标签文件

dataviewjs
// 获取所有Markdown文件
const mdFiles = dv.pages('"4.Apply"').file

// 过滤未设置标签的文件
const untaggedFiles = mdFiles.filter(f => {
    const page = dv.page(f.path)
    // 检查是否存在tags字段,并验证是否有效
    return !page?.tags || 
          (Array.isArray(page.tags) && page.tags.length === 0) ||
          (typeof page.tags === 'string' && page.tags.trim() === "")
})

// 显示结果
if (untaggedFiles.length > 0) {
    dv.header(4, "未设置标签的文件 (" + untaggedFiles.length + "个)")
    dv.list(untaggedFiles.map(f => dv.fileLink(f.path)))
} else {
    dv.paragraph("🎉 所有Markdown文件都已设置标签!")
}

所有标签统计

dataviewjs
dv.header(2,"标签统计");
//let path="4.Apply"; //  设置根目录路径,请替换
let pages = dv.pages(``);//  设置根目录路径,请替换
//let pages = dv.pages(`"4.Apply"`);//  设置根目录路径,请替换
let publishPages=pages.filter(a => a.publish == true);//已发布,可替换 "publish" 为您实际yaml属性
let toPublishPages=pages.filter(a => a.publish == false);//未发布,可替换 "publish" 为您实际yaml属性

//数量统计部分
let i = [pages.length,
        toPublishPages.length,
        publishPages.length,
        pages.file.etags.distinct().length];
dv.paragraph(`共有 **${i[0]}** 篇相关笔记,未发布**${i[1]}** 篇,已发布**${i[2]}** 篇,标签 **${i[3]}** 个`);

// ================== 标签云样式配置 ==================
dv.el('style', `
.dynamic-query-container {
    position: relative;
    min-height: 200px;
    padding: 20px;
    background: var(--background-primary);
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
`);

// ================== 标签云功能实现 ==================
const container = dv.el('div', '', { cls: 'dynamic-query-container' });

// 自动执行标签云查询
const dynamicQuery = async () => {
    const resultDiv = dv.el('div', '', { cls: 'result' });
    
    // 固定查询路径
    await dv.view("5.Archives/1.resources/Js/tagcloud", {
        values: pages.filter(p => p.file.tags)
    }, resultDiv);
    container.appendChild(resultDiv);
}

// 直接执行标签云查询
setTimeout(dynamicQuery, 100);

标签云-可指定文件夹

dataviewjs
// ================== 样式配置 ==================
const style = dv.el('style', `
.dynamic-query-container {
    position: relative;
    min-height: 200px;
}
.control-panel {
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
    gap: 12px;  /* 增加间距 */
    align-items: center;
    background: var(--background-primary);
    padding: 12px;  /* 增加内边距 */
    border-radius: 10px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 100;
}
.folder-select {
    padding: 10px 16px;  /* 加大内边距 */
    border: 2px solid var(--interactive-accent);  /* 加粗边框 */
    border-radius: 8px;
    background: var(--background-primary);
    color: var(--text-normal);
    font-size: 16px;  /* 增大字号 */
    width: 180px;     /* 加宽容器 */
    height: 44px;     /* 固定高度 */
}
.query-btn {
    padding: 12px 24px;  /* 加大按钮尺寸 */
    border-radius: 8px;
    background: var(--interactive-accent);
    color: var(--text-on-accent);
    border: none;
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 16px;      /* 按钮字号 */
    font-weight: 600;     /* 加粗文字 */
    letter-spacing: 0.5px;/* 字间距 */
}
.query-btn:hover {
    transform: scale(1.05);
    box-shadow: 0 4px 16px rgba(var(--interactive-accent-rgb), 0.3);
}
`);

// ================== 功能实现 ==================
// 创建容器
const container = dv.el('div', '', { cls: 'dynamic-query-container' });

// 创建控制面板
const controlPanel = dv.el('div', '', { cls: 'control-panel' });

// 路径选择器
const folderSelector = dv.el('select', '', { cls: 'folder-select' });
const FOLDER_OPTIONS = {
    '"0.Atlas"': '📌 Atlas',
    '"1.Acquire"': '🔍 Acquire',
    '"2.Action"': '🚀 Action',
    '"3.Atom"': '🧩 Atom',
    '"4.Apply"': '⚡ Apply',
    '"5.Archives"': '🗃️ Archives',
    '"/"': 'Vault根目录'
};

Object.entries(FOLDER_OPTIONS).forEach(([path, name]) => {
    const option = dv.el('option', name);
    option.value = path;
    if (path === '"4.Apply"') option.selected = true;
    folderSelector.appendChild(option);
});

// 查询按钮
const queryBtn = dv.el('button', '🔎 执行查询', { cls: 'query-btn' });

// 动态查询函数
const dynamicQuery = async (folderPath) => {
    container.querySelector('.result')?.remove();
    const resultDiv = dv.el('div', '', { cls: 'result' });
    
    await dv.view("5.Archives/1.resources/Js/tagcloud", {
        values: dv.pages(folderPath).filter(p => p.file.tags)
    }, resultDiv);
}

// 事件绑定
queryBtn.addEventListener('click', () => {
    // 清除旧结果
    while (dv.container.children.length > 2) {
        dv.container.lastChild.remove();
    }
    // 执行新查询
    dynamicQuery(folderSelector.value);
});

// 初始加载后自动查询
setTimeout(() => dynamicQuery('"4.Apply"'), 100);

// 组装界面
controlPanel.appendChild(folderSelector);
controlPanel.appendChild(queryBtn);
container.appendChild(controlPanel);

仓库统计

dataviewjs
dv.header(2,"文章统计");
let ftMd = dv.pages("").file.sort(t => t.cday)[0]
let total = parseInt([new Date() - ftMd.ctime] / (60*60*24*1000))
let totalDays = "使用 *Obsidian* "+"**"+total+"**天,"
dv.paragraph(totalDays)
//.length统计数量
let i = [dv.pages('!"4.Extra/Template"').length,dv.pages(`"2.Calendar"`).length,dv.pages(`"4.Extra"`).length,
         dv.pages().file.etags.distinct().length]
// console.log(dv.pages())
dv.paragraph(`共有 **${i[0]}** 篇笔记,Calendar笔记 **${i[1]}** 篇,附件 **${i[2]}** 个,标签 **${i[3]}** 个`)
dataviewjs
let ftMd = dv.pages("").file.sort(t => t.cday)[0]
let total = parseInt([new Date() - ftMd.ctime] / (60*60*24*1000))
let totalDays = "您已使用 ***Obsidian*** "+total+" 天,"
let nofold = '!"misc/templates"'
let allFile = dv.pages(nofold).file
let totalMd = "共创建 "+ allFile.length+" 篇笔记"
let totalTag = allFile.etags.distinct().length+" 个标签"
let totalTask = allFile.tasks.length+"个待办。 "
dv.paragraph(
	totalDays + totalMd + "、" + totalTag + "、" + totalTask
)

所有带关键词的行

dataviewjs
//输出所有带有关键词的行
//使用时修改关键词即可
const term = "ACID"
const files = app.vault.getMarkdownFiles()
const arr = files.map(async ( file) => {
	const content = await app.vault.cachedRead(file)
	const lines = content.split("\n").filter(line => line.contains(term))
	return lines
})
Promise.all(arr).then(values => dv.list(values.flat()))

倒计时

dataviewjs
// 修改其中的时间,可以输出当前离倒计时的时间差。
const setTime = new Date("2024/6/15 08:00:00");
const nowTime = new Date();
const restSec = setTime.getTime() - nowTime.getTime();
const day = parseInt(restSec / (60*60*24*1000));
const str = day + "天"
dv.paragraph(str);

Todo 文件一行输出

dataviewjs
//控制台调试
console.log(dv.pages("#Todo"))
//dv.paragraph生成段落
dv.paragraph(`${dv.pages("#Todo").file.link}`)

任务列表

dataviewjs
//dv.taskList生成任务列表
//console.log(dv.pages("#Task"))
dv.taskList(dv.pages("#Task").file.tasks) 

待办列表

dataviewjs
dv.header(3,"待办列表");
//dv.list生成列表
dv.list(dv.pages("#Todo").map(p=>p.file.link));

最近一周文件列表

dataviewjs
//查询结果有误
dv.header(5,"最近一周");
dv.list(
	dv.pages(``)
	.filter(p=>moment(p.created).diff(moment(),'days')<=7)
	.map(p=>p.file.link+' - '+p.created));

2024 年 8 月文件列表

dataviewjs
dv.header(3,"2024年7月文件列表");
//2024年文件
//dv.list()生成List
dv.list(
	//获取符合条件的文件数组
	dv.pages(``)
		//筛选符合条件的子数组
		.filter(p=>moment(Number(p.file.cday)).get("year")==2024 
		&& moment(Number(p.file.cday)).get("month")==7)
		//降序排序
		.sort(p=>p.file.cday,'desc')
		//.map()类似for循环
		.map(p=>moment(Number(p.file.cday)).format('yyyy-MM-DD')+' >> '+p.file.link)
)

某年某月文件列表

dataviewjs
dv.header(3,"2024年8月文件列表");
dv.list(
    // 获取符合条件的文件数组
    dv.pages("")
        // 筛选符合条件的子数组(将 'file.cday' 转换为日期格式)
        .filter(p => {
            const date = moment(p.created);
            // 筛选符合条件的子数组(将 'file.cday' 转换为日期格式)
            // 月份比较不准,总是大一,问题未知(24年1月)
            return date.year() ==2024 && date.month() ==0;
        })
        // 降序排序
        .sort(p => p.created, 'desc')
        // 使用 map 转换输出格式并处理日期(确保使用 `format` 方法正确解析)
        .map(p => {
            const formattedDate = moment(p.created).format('YYYY-MM-DD');
            return `${formattedDate} >> ${p.file.link}`;
        })
)

文件夹下文件列表

dataviewjs
//写法1
//dv.pagePaths()获取文件目录数组
for(let i of dv.pagePaths(`"1.Atlas"`).groupBy(p=>p.split("/")[1])){
	let a = dv.pages(`"1.Atlas/${i.key}"`).length
	dv.paragraph(`### ${i.key} --**${a}**篇`);
	dv.list(
		dv.pages(`"1.Atlas"`)
			.filter(p=>p.file.folder.split("/")[1]==i.key)
			//cday写法 .map(p=>moment(Number(p.file.cday)).format('yyyy-MM-DD')+' >> '+p.file.link)
			.map(p=> p.file.link + '>>' +p.created +' - '+moment().diff(moment(p.created),'days')+'天')
	);
}
dataviewjs
//写法2,优先使用
let pageGroups = dv.pagePaths(`"1.Atlas"`).groupBy(p => p.split("/")[1]);
for (let i of pageGroups) {
    let pagesInGroup = dv.pages(`"1.Atlas/${i.key}"`);
    // 使用 pagesInGroup 替换重复的获取操作
    dv.paragraph(`### ${i.key} --**${pagesInGroup.length}**篇`);
    dv.list(pagesInGroup.map(p => {
        let daysSince = moment(p.created).diff(moment(), 'days');
        return p.file.link + '>>' +p.created + ' - ' + `${daysSince}` + '天';
    }));
}

MySQL 文件夹列表

dataviewjs
//MySQL文件夹总览
let pageGroups = dv.pagePaths(`"2.Calendar/7.todo/1.Study/MySQL"`).groupBy(p => p.split("/")[4]);
console.log(pageGroups);
for (let i of pageGroups) {
    let pagesInGroup = dv.pages(`"2.Calendar/7.todo/1.Study/MySQL/${i.key}"`);
    // 使用 pagesInGroup 替换重复的获取操作
    dv.paragraph(`### ${i.key} --**${pagesInGroup.length}**篇`);
    dv.list(pagesInGroup.map(p => {
        let daysSince = moment(p.created).diff(moment(), 'days');
        return p.file.link + '>>' +p.created + ' - ' + `${daysSince}` + '天';
    }));
}

Atlas 文件夹 Table

dataviewjs
dv.header(1,"table任务");
// 首先获取所有页面的路径
let allPaths = dv.pagePaths(`"1.Atlas"`);

// 对文件夹进行分组并处理每个子集
for(let i of allPaths.groupBy(p=>p.split("/")[1])){
    let a = dv.pages(`"1.Atlas/${i.key}"`).length;
    dv.paragraph(`### ${i.key} --**${a}**篇`);
    // 过滤当前文件夹下的页面,并计算从创建以来的天数和获取实际创建日期
    let pageData = dv.pages(`"1.Atlas"`)
                        .filter(p => p.file.folder.split("/")[1] == i.key)
                        .map(p => ({
                            title: i.key,
                            pageName: p.file.link,
                            sinceCreated: moment().diff(moment(p.created), 'days'),
                            created: p.created
                        }));
    // 创建并展示一个表格,用于当前文件夹下的页面数据
    dv.table(['文件夹', '文件名', '创建天数', '创建日期'],
    pageData.title,pageData.pageName,pageData.sinceCreated,pageData.created);   
}

指定多个文件夹 Table

dataviewjs
{
dv.header(1,"指定多个文件夹Table");
// 首先获取所有页面的路径
let allPaths = [
    { key: "1.Atlas" },
    { key: "4.Extra" }
];
// 对文件夹进行分组并处理每个子集
for(let i of allPaths){
    let a = dv.pages(`"${allPaths[0].key}"`).length;
    dv.paragraph(`### ${i.key} --**${a}**篇`);
    // 过滤当前文件夹下的页面,并计算从创建以来的天数和获取实际创建日期
    let pageData = dv.pages(``)
                        .filter(p => p.file.folder.split("/")[0] == i.key)
                        .map(p => ({
                            pageName: p.file.link,
                            path: p.file.folder,
                            sinceCreated: moment().diff(moment(p.created), 'days'),
                            created: p.created
                        }));
    // 创建并展示一个表格,用于当前文件夹下的页面数据
    dv.table(['文件名','文件路径','创建天数', '创建日期'],
    pageData.pageName,pageData.path,pageData.sinceCreated,pageData.created);   
}}

仓库文件夹 Table

dataviewjs
dv.header(1,"仓库文件夹Table");
// 首先获取所有页面的路径
let allPaths = dv.pagePaths(``);
// 对文件夹进行分组并处理每个子集
for(let i of allPaths.groupBy(p=>p.split("/")[0])){
    let a = dv.pages(`"${i.key}"`).length;
    dv.paragraph(`### ${i.key} --**${a}**篇`);
    // 过滤当前文件夹下的页面,并计算从创建以来的天数和获取实际创建日期
    let pageData = dv.pages(``)
                        .filter(p => p.file.folder.split("/")[0] == i.key)
                        .map(p => ({
                            pageName: p.file.link,
                            path: p.file.folder,
                            sinceCreated: moment().diff(moment(p.created), 'days'),
                            created: p.created
                        }));
    // 创建并展示一个表格,用于当前文件夹下的页面数据
    dv.table(['文件名', '文件路径','创建天数', '创建日期'],
    pageData.pageName,pageData.path,pageData.sinceCreated,pageData.created);   
}

文章统计-列表

dataviewjs
dv.header(2,"文章统计");
let path="AA";
let paths = dv.pagePaths(`"${path}"`);
let pages = dv.pages(`"${path}"`);

let s=["Todo","Organize","Rewrite","Explor","Apply","Done"];
let todoPages=pages.filter(a => a.status == s[0]);
let orangizePages=pages.filter(a => a.status == s[1]);
let rewritePages=pages.filter(a => a.status == s[2]);
let explorPages=pages.filter(a => a.status == s[3]);
let applyPages=pages.filter(a => a.status == s[4]);
let donePages=pages.filter(a => a.status == s[5]);
let cols=['文件名','id','标签','状态','创建天数'];

//.length统计数量
//数量统计
let i = [pages.length,
		todoPages.length,
		orangizePages.length,
		rewritePages.length,
		explorPages.length,
		applyPages.length,
		donePages.length,
		pages.file.etags.distinct().length]
dv.paragraph(`共有 **${i[0]}** 篇笔记,${s[0]}**${i[1]}** 篇,${s[1]}**${i[2]}** 篇,${s[2]}**${i[3]}** 篇,${s[3]}**${i[4]}** 篇,${s[4]}**${i[5]}** 篇,${s[5]}**${i[6]}** 篇,标签 **${i[7]}** 个`)

// 所有的标签
dv.paragraph(pages.file.tags.distinct()
	  .map(t => {return `[${t}](${t})`})
	  .array().sort().join(" | "));

dv.table(cols,tableByDay(pages));

function tableByDay(pages) {
    return pages.sort((a, b) => moment(b.created).unix() - moment(a.created).unix())
	    .map(p => ([
                            p.file.link,
                            p.id,
                            p.tags,
                            //p.file.folder,
                            p.status,
                            moment().diff(moment(p.created), 'days')
                        ]))
}

文章统计-分组

dataviewjs
dv.header(2,"文章统计");
let path="2.Collection/5.Java/6.DB/MySQL";
//let path="3.Cards/MySQL";
let paths = dv.pagePaths(`"${path}"`);
let pages = dv.pages(`"${path}"`);
let filePaths=paths.groupBy(p=>p.split("/")[4]);

let todoPages=pages.filter(a => a.status == "Todo");
let donePages=pages.filter(a => a.status == "Done");
let cols=['文件名','id','标签', '状态','创建天数', '创建日期'];

//数量统计
let i = [pages.length,
		pages.filter(a => a.status == "Todo").length,
		pages.filter(a => a.status == "Done").length,
		pages.file.etags.distinct().length]
dv.paragraph(`共有 **${i[0]}** 篇相关笔记,Todo**${i[1]}** 篇,Done**${i[2]}** 篇,标签 **${i[3]}** 个`)

// 所有的标签
dv.paragraph(pages.file.tags.distinct()
	  .map(t => {return `[${t}](${t})`})
	  .array().sort().join(" | "));

//TodoTable
dv.header(2,"TodoTable -- **"+todoPages.length+"**篇");
table(cols,todoPages);

//DoneTable
dv.header(2,"Table -- **"+pages.length+"**篇");
// 对文件夹进行分组并处理每个子集
for(let i of filePaths){
//.filter(p => p.status !== "Todo")
    let a = dv.pages(`"${path}/${i.key}"`);
    dv.paragraph(`### ${i.key} --**${a.length}**篇`);
	table(cols,a);
}

function table(cols,pages) {
    dv.table(cols,pages.sort((a, b) => moment(b.created).unix() - moment(a.created).unix())
	    .map(p => ([
					p.file.link,
					p.id,
                    p.tags,
                    p.status,
                    moment().diff(moment(p.created), 'days'),
                    p.created
                    ])));
}

使用dataview分组查询所有已发布的笔记

dataviewjs
dv.header(2,"文章统计情况");

let path="4.Apply"; //  设置根目录路径,请替换
let paths = dv.pagePaths(`"4.Apply"`);//  设置根目录路径,请替换
let pages = dv.pages(`"4.Apply"`);//  设置根目录路径,请替换


let filePaths=paths.groupBy(p=>p.split("/")[1]); //  按第一级子文件夹名称分组路径,可替换 "1" 为您实际层次目录

let publishPages=pages.filter(a => a.publish == true);//已发布,可替换 "publish" 为您实际yaml属性
let toPublishPages=pages.filter(a => a.publish == false);//未发布,可替换 "publish" 为您实际yaml属性

let loopCount = 1;// 初始化循环计数器 
let cols=['文件名','是否发布','标签', '状态','创建天数', '创建日期','发布日期'];//预设的输出table表头,可替换

//自定义排序部分
let letters = "*abcdefghjklmnopqrstwxyz".toLocaleUpperCase().split('');
let zh = "阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀".split('');

var isNumber = function(temp){
    let re = /[0-9]/;
    return re.test(temp);
};

var isChar = function(temp){
    let re = /[a-zA-Z]/;
    return re.test(temp);
};

var isChinese = function(temp){
    let re = /[^\u4E00-\u9FA5]/;
    return re.test(temp) ? false : true;
};
//  mySort 函数,将文件按照文件名排序,优先数字,其次字母,最后汉字
function mySort(dvPages, letters, zh) { 
    let sortedPages = [];
    letters.forEach((e,i) => {
        let key = (e == "*") ? "0~9" : e;
        let currData = new Array();
        dvPages.forEach(b => {
            let fileName = b.file.name;
            if (fileName) {
                let initial = fileName.charAt(0);
                if(i == 0 && isNumber(initial)){
                    currData.push(b);
                } else if (i != 0 && isChar(initial) && e == initial.toLocaleUpperCase()){
                    currData.push(b);
                } else if (i != 0 && isChinese(initial)){
                    if(initial.localeCompare(zh[i]) == -1 && (!zh[i-1] || zh[i-1].localeCompare(initial) <= 0)){
                        currData.push(b);
                    }
                }
            }
        });
        if(currData.length > 0){
            currData.sort((a, b) => { //  修改后的排序函数
                let fileNameA = a.file.name;
                let fileNameB = b.file.name;

                // 提取文件名中的数字部分进行数值比较
                let numA = parseInt(fileNameA.match(/^(\d+)/)?.[1]); // 正则提取文件名开头的数字
                let numB = parseInt(fileNameB.match(/^(\d+)/)?.[1]); // 正则提取文件名开头的数字

                // 如果都能提取到数字,则进行数值比较
                if (!isNaN(numA) && !isNaN(numB)) {
                    return numA - numB; // 数值升序排序
                } else {
                    //  如果无法提取数字,则 Fallback 到字符串排序 (字典序)
                    if (fileNameA < fileNameB) return -1;
                    if (fileNameA > fileNameB) return 1;
                    return 0;
                }
            });
            sortedPages = sortedPages.concat(currData);
        }
    });
    return sortedPages;
}

//数量统计部分
let i = [pages.length,
        toPublishPages.length,
        publishPages.length,
        pages.file.etags.distinct().length];
dv.paragraph(`共有 **${i[0]}** 篇相关笔记,未发布**${i[1]}** 篇,已发布**${i[2]}** 篇,标签 **${i[3]}** 个`);

// 所有的标签
dv.paragraph(pages.file.tags.distinct()
	  .map(t => {return `[${t}](${t})`})
	  .array().sort().join(" | "));

// 按照层级循环遍历根目录下的子文件夹
for (const i of filePaths) {
	//  输出三级标题,有序显示当前子文件夹名称
    dv.header(3, `${loopCount} : ${i.key}`); 

    //  动态查询每个子文件夹下的已发布页面
    let currentDvPages = dv.pages(`"${path}/${i.key}"`)
    //.filter(a => a.publish == true);

    //  调用 mySort 函数对当前子文件夹的页面进行排序
    const sortedPages = mySort(currentDvPages, letters, zh);

    // 输出当前子文件夹的排序结果
    if (sortedPages.length > 0) {
        table(cols,sortedPages);
    } else {
        dv.paragraph(` ${i.key} 下没有符合条件的文件`);
    }
     dv.paragraph("---"); //  添加分隔线,区分不同子文件夹的输出
     // 循环计数器递增     
     loopCount++;
}

//输出表格,可替换成您实际yaml属性
function table(cols,pages) {
    dv.table(cols,pages
    .map(p => ([
            p.file.link,
            p.publish,
            p.tags,
            p.status,
            moment().diff(moment(p.created), 'days'),
            p.created,
            p.date
            ]))
            );
}

状态统计

dataviewjs
let allPaths = ["0.Atlas","1.Projects","2.Areas","3.Resources","4.Archives","5.a",]
let s=["Todo","Organize","Rewrite","Explor","Apply","Done"];
//let days=[0,1,3,7,30];

//let ftMd = dv.pages(`""`).file.sort(t => t.cday)[0];
//let noteCreateTime = new Date(ftMd.ctime);
//let total = parseInt([new Date() - noteCreateTime] / (60*60*24*1000))

//let paths = dv.pagePaths(`-"${allPaths[0]}" and -"${allPaths[3]}" and -"${allPaths[4]}"`);
//let pages = dv.pages(`-"${allPaths[0]}" and -"${allPaths[3]}" and -"${allPaths[4]}"`);
let paths = dv.pagePaths(`-"${allPaths[5]}"`);
let pages = dv.pages(`-"${allPaths[5]}"`);


dv.header(2,"文章统计");
let formattedToday = moment().format('YYYY年MM月DD日');
let firstDay = pages.sort((a, b) => moment(a.created).unix() - moment(b.created).unix())[0];
let total=moment().diff(moment(firstDay.created), 'days');
let totalDays = "今天是"+formattedToday+",最早的笔记:"+firstDay.file.link+",始于"+firstDay.created+",记录 "+"**"+total+"** 天!"

let todoPages=pages.filter(a => a.status == s[0]);
// 以下内容可按需开启查询
let orangizePages=pages.filter(a => a.status == s[1]);
let rewritePages=pages.filter(a => a.status == s[2]);
let explorPages=pages.filter(a => a.status == s[3]);
let applyPages=pages.filter(a => a.status == s[4]);
let donePages=pages.filter(a => a.status == s[5]);
let publishedPages=pages.filter(a => a.publish === true);
let noPages=pages.filter(a => a.publish !== true);
let cols=['文件名','标签','文件路径', '状态','创建天数', '创建日期'];

// 统计天数
dv.paragraph(totalDays);

//.length统计数量
//数量统计
let i = [pages.length,
		todoPages.length,
		orangizePages.length,
		rewritePages.length,
		explorPages.length,
		applyPages.length,
		donePages.length,
		pages.file.etags.distinct().length]
dv.paragraph(`共有 **${i[0]}** 篇笔记,${s[0]}**${i[1]}** 篇,${s[1]}**${i[2]}** 篇,${s[2]}**${i[3]}** 篇,${s[3]}**${i[4]}** 篇,${s[4]}**${i[5]}** 篇,${s[5]}**${i[6]}** 篇,标签 **${i[7]}** 个`)

// 所有的标签
dv.paragraph(pages.file.tags.distinct()
	  .map(t => {return `[${t}](${t})`})
	  .array().sort().join(" | "));

//dv.header(3,s[0]);
//dv.table(cols,tableByDay(todoPages));

//dv.header(3,s[1]);
//dv.table(cols,tableByDay(orangizePages));

//dv.header(3,s[2]);
//dv.table(cols,tableByDay(rewritePages));

//dv.header(3,s[3]);
//dv.table(cols,tableByDay(explorPages));

//dv.header(3,s[4]);
//dv.table(cols,tableByDay(applyPages));

//dv.header(3,s[5]);
//dv.table(cols,tableByDay(donePages));

dv.header(3,'publish');
dv.table(cols,tableByDay(publishedPages));


function tableByDay(pages) {
    return pages.sort((a, b) => moment(b.created).unix() - moment(a.created).unix())
	    .map(p => ([
                            p.file.link,
                            p.tags,
                            p.file.folder,
                            p.status,
                            moment().diff(moment(p.created), 'days'),
                            p.created
                        ]))
}

关联文章


文章作者: huan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 huan !
  目录