有一个复选框,选上和没选上两种结果
列出全文所有的h2和h3级标题
-如果只有h2没有h3则h2也不列出
列出全文没有问号的h3级标题及其所在的h2级标题
-同上
利用复选框实现了单一筛选
如果需要改变筛选条件,可以用deepseek 全复制提条件即可
以下是代码
// 使用 plugin 的持久化存储
const store = dv.app.plugins.plugins['dataview']?.storage;
// 创建交互式开关
const toggleContainer = dv.el('div', '', { cls: 'toggle-container' });
// 从存储读取状态(默认不显示含问号标题)
let showAll = store?.getValue('showAllHeadings') || false;
// 创建复选框
const checkbox = toggleContainer.createEl('input', {
type: 'checkbox',
cls: 'heading-toggle',
checked: showAll
});
toggleContainer.createEl('label', {
text: ' 显示包含问号的标题',
cls: 'toggle-label'
});
// 点击时保存状态并重新渲染
checkbox.addEventListener('change', async (e) => {
showAll = e.target.checked;
if (store) {
await store.setValue('showAllHeadings', showAll);
} else {
localStorage.setItem('showAllHeadings', showAll);
}
await renderHeadings(checkbox.checked);
});
// 主渲染函数 - 现在接受 showAll 参数
async function renderHeadings(showAll) {
// 清空之前的内容(保留开关容器)
const children = Array.from(dv.container.children);
for (const child of children) {
if (!child.classList.contains('toggle-container')) {
dv.container.removeChild(child);
}
}
// 获取文件内容
const currentFile = app.workspace.getActiveFile();
const content = await app.vault.read(currentFile);
// 处理标题
const headings = content.split('\n')
.map((line, i) => {
const match = line.match(/^(##|###)\s(.+)$/);
if (!match) return null;
const text = match[2].trim();
return {
text,
line: i,
level: match[1].length,
hasQuestion: text.includes('?') || text.includes('?')
};
})
.filter(h => h && (showAll || !h.hasQuestion));
// 组织标题层级关系
const groupedHeadings = [];
let currentH2 = null;
for (const h of headings) {
if (h.level === 2) {
if (currentH2 && currentH2.h3s.length > 0) {
groupedHeadings.push(currentH2);
}
currentH2 = { ...h, h3s: [] };
} else if (h.level === 3 && currentH2) {
currentH2.h3s.push(h);
}
}
if (currentH2 && currentH2.h3s.length > 0) {
groupedHeadings.push(currentH2);
}
// 渲染结果
if (groupedHeadings.length) {
const list = dv.el('ul', '');
groupedHeadings.forEach(group => {
const h2Item = dv.el('li', '');
const h2Link = dv.el('a', group.text, {
cls: 'internal-link h2-link', // 添加 h2-link 类
attr: { 'data-line': group.line }
});
h2Link.onclick = (e) => {
e.preventDefault();
app.workspace.activeLeaf.openFile(currentFile, {
eState: { line: group.line }
});
};
h2Item.appendChild(h2Link);
list.appendChild(h2Item);
group.h3s.forEach(h3 => {
const h3Item = dv.el('li', '');
const h3Link = dv.el('a', ' ' + h3.text, {
cls: 'internal-link',
attr: { 'data-line': h3.line }
});
h3Link.onclick = (e) => {
e.preventDefault();
app.workspace.activeLeaf.openFile(currentFile, {
eState: { line: h3.line }
});
};
h3Item.appendChild(h3Link);
list.appendChild(h3Item);
});
});
dv.container.appendChild(list);
} else {
dv.paragraph(showAll
? "❌ 未找到任何有效的H2/H3标题组合"
: "❌ 未找到不含问号的H2/H3标题组合");
}
}
// 初始渲染 - 传入存储的状态
await renderHeadings(showAll);
// 添加样式
dv.el('style', `
.toggle-container { margin-bottom: 15px; }
.heading-toggle { margin-right: 8px; }
.toggle-label { cursor: pointer; }
.internal-link { text-decoration: underline; }
/* 新增 H2 链接样式 */
.h2-link {
font-size: 1.5em;
font-weight: bold;
}
`);
使用建议存为.js文件
然后通过
dv.view("交互")
调取
如果直接用在文件内,别忘了加dataviewjs