如何通过dataview将所有标签汇聚起来

想要在HOME页面将所有标签列出来。
我的标签整理得还不错,边栏列表式标签太长不方便,希望可以放到页面中。
样式类似这样:

标签A (间隔)(间隔) 标签B (间隔)(间隔) 标签C (间隔)(间隔) 标签D
(缩进)标签a(缩进)标签b(缩进)(缩进)(缩进)标签c
(缩进)标签a(缩进)标签b

空格会被吞,只能这样,带括号的间隔和缩进不看,就是类似一个表格,按照标签层级显示出来就行了。

我记得有个插件专门用来汇总所有标签到页面内的,忘记叫什么了,楼主可以找找

仅供参考,如果想把子标签缩进处理,可以用/分割后进一步处理。

```dataviewjs
const tags = app.metadataCache.getTags();
const chunkArray = (array, size) => {
  let result = [];
  array.reduce((acc, currentValue, index) => {
    if (index % size === 0) acc.push([]);
    acc[acc.length - 1].push(currentValue);
    return acc;
  }, result);
  return result;
}

dv.table([], chunkArray(Object.keys(tags), 4))
```

目前这样还达不到正常使用的地步,但我不会改。

需要正确的拆分、分级显示,才有使用价值。

这种是你想要的吗?我用dataviewjs写的markdown面板

这个跟ob自带标签页面好像是一样的,但如果是通过dataviewjs实现的,那就可以放到md文件中,基本实现我的需求了,如果能全部子标签默认展开就好了(万一实现不了也行,也能用,求代码)

和官方不一样,官方标签下没有文件,通过搜索查看文件,我这个有,直接查看文件,另外,比官方功能多。

支持默认全部展开或折叠,稍等,我空了整理下,修正下bug再分享。

1 个赞

OK,多谢

期待……

我那个脚本较为复杂,针对你的需求未必适合,改动也有难度,我根据你的需求,整理了一个简洁版,不知道是否你想要的效果,如下

代码:

```dataviewjs
// 获取所有tags
let tags = app.metadataCache.getTags();
//是否区分大小写,true区分,false不区分
const isCaseSensitive = true;
const tree = {};
let content = '';
// 按嵌前缀排序
const sortByPrefix = (arr) => {
    return arr.sort((a, b) => {
        // 分割字符串获取前缀
        const prefixA = a.split('/')[0];
        const prefixB = b.split('/')[0];
        
        // 比较前缀
        if (prefixA !== prefixB) {
            return prefixA.localeCompare(prefixB); // 按照前缀字母顺序排序
        } else {
            // 如果前缀相同,则比较整个字符串
            return a.localeCompare(b);
        }
    });
}
tags = Object.keys(tags);
tags = sortByPrefix(tags);
// 嵌套输出标签列表
tags.forEach(tag => {
	if(!isCaseSensitive) tag = tag.toLowerCase();
    let subs = tag.split('/');
    let currentNode = tree;
    let path = '';
    subs.forEach((sub, index) => {
        path += (index ? '/' : '') + sub;
        // 如果不在目录结构的列表才输出,防止重复输出父分类和祖先分类
        if(!currentNode[sub]){
            //输出tag
            content += `${"\t".repeat(index)}- ${path}\n\n`
        }
        // 实时计算目录嵌套结构
        if (!currentNode[sub]) {
            currentNode[sub] = {};
        }
        currentNode = currentNode[sub];
    });
});
//输出样式
const styleText = `
.my-all-tags{
    overflow-x: hidden;
}
.my-all-tags li {
    float: left;
    display: inline-block;
    width: 215px;
    line-height: 40px;
    list-style-type: none;
}
.my-all-tags li a{
	font-size: 16px;
}
.my-all-tags .tag-sub-prefix{
	display: none;
}
`;
const style = document.head.querySelector("#my-all-tags");
if(style) style.remove();
document.head.appendChild(
	createEl("style", {
		attr: { id: "my-all-tags" },
		text: styleText,
		type: "text/css",
	})
);
//生成列表
const tagsList = dv.el('div', content, {attr: {class: "my-all-tags"}});
requestAnimationFrame(() => {
    // 去掉子标签前缀
	tagsList.querySelectorAll('li a[href*="/"]').forEach((a)=>{
	    const subTags = a.innerHTML.split('/');
	    const tagName = subTags.pop();
	    a.innerHTML = '<span class="tag-sub-prefix">' + subTags.join('/') + '/</span>' + tagName;
	});
});
```
1 个赞

这段代码有点问题。

我的标签有

日记/2021 日记/2022 日记/2023
日常 写作

显示的结构有问题
日记 下面显示2021 日常 下面显示 2022 2023 ,可 日常 是独立标签
还有就是会在 写作 下面 显示 日常
类似这样的问题,整个嵌套层级完全不按实际来

这就不知道了,我这边没问题,无法重现,你根据你自己的环境调整吧。有可能是样式问题,你用官方默认样式试试。

或者按Ctrl+Shift+I打开控制台(Mac: option+command+i),然后打印你的标签结构我看看,像下面这样打印,参考下图。

console.log(app.metadataCache.getTags())

注意:在打印结果上右键,复制object粘贴出来,不要截图。

搞定了,是复制代码造成的问题。
论坛上复制代码直接粘贴到ob,格式会改变,通过windows自带的记事本中转一下就好了。

请问大佬,你这个汇总出来的标签不知道是什么规则排序的,怎么做到按名称排序标签呢?

另外,获取指定文件夹里面的标签,代码是怎样的?没有一点代码基础,实在恼火,望大神解答

排序不重要,因为只能整体设置正序或倒序排列,没什么意义。

// 获取所有tags
let tags = app.metadataCache.getTags();
//是否区分大小写,true区分,false不区分
const isCaseSensitive = true;
const tree = {};
let content = '';
// 按嵌前缀排序
const sortByPrefix = (arr) => {
    return arr.sort((a, b) => {
        // 分割字符串获取前缀
        const prefixA = a.split('/')[0];
        const prefixB = b.split('/')[0];
        
        // 比较前缀
        if (prefixA !== prefixB) {
            return prefixA.localeCompare(prefixB); // 按照前缀字母顺序排序
        } else {
            // 如果前缀相同,则比较整个字符串
            return a.localeCompare(b);
        }
    });
}
tags = Object.keys(tags);
tags = sortByPrefix(tags);
// 嵌套输出标签列表
tags.forEach(tag => {
	if(!isCaseSensitive) tag = tag.toLowerCase();
    let subs = tag.split('/');
    let currentNode = tree;
    let path = '';
    subs.forEach((sub, index) => {
        path += (index ? '/' : '') + sub;
        // 如果不在目录结构的列表才输出,防止重复输出父分类和祖先分类
        if(!currentNode[sub]){
            //输出tag
            content += `${"\t".repeat(index)}- ${path}\n\n`
        }
        // 实时计算目录嵌套结构
        if (!currentNode[sub]) {
            currentNode[sub] = {};
        }
        currentNode = currentNode[sub];
    });
});
//输出样式

/* 添加CSS样式 */
const styleText = `
.my-all-tags ul {
    padding: 0;
    margin: 0;
    list-style-type: none;  /* 移除列表默认样式 */
}

.my-all-tags ul li {
    width: calc(100% - 10px); /* 每个列表项的宽度,这里假设三列布局 */
    box-sizing: border-box;
    margin: 5px; /* 主列表项的外边距 */
    padding: 5px; /* 内边距 */
    background: #f5f5f5; /* 主列表项的背景颜色 */
    float: left; /* 使列表项并排显示 */
}

/* 子列表项不设置外边距和背景色 */
.my-all-tags ul li ul {
    padding: 0;
    margin: 0;
    list-style-type: none;
    background: transparent; /* 确保子列表无背景色 */
}

.my-all-tags ul li ul li {
    width: auto; /* 子列表项宽度自适应 */
    margin: 5px 0; /* 子列表项的上下边距 */
    padding-left: 20px; /* 子列表项的左边距,用于缩进 */
    background: transparent; /* 子列表项无背景色 */
}

.my-all-tags li a {
    font-size: 16px;
    text-decoration: none;
    color: #333;
    display: block;
    padding: 5px; /* 链接内边距 */
    border:0;
}

.my-all-tags li a:hover{
	border:0;
	color:#999;
}

/* 隐藏子标签前缀,如果存在的话 */
.my-all-tags .tag-sub-prefix {
    display: none;
}
`;

// 确保style元素存在且唯一
const styleId = "my-all-tags-style";
let style = document.getElementById(styleId);
if (style) {
    style.parentNode.removeChild(style); // 移除旧的style元素
}
style = document.createElement("style");
style.id = styleId;
style.type = "text/css";

// 添加CSS样式到页面
style.appendChild(document.createTextNode(styleText));
document.head.appendChild(style);

//生成列表
const tagsList = dv.el('div', content, {attr: {class: "my-all-tags"}});
requestAnimationFrame(() => {
    // 去掉子标签前缀
	tagsList.querySelectorAll('li a[href*="/"]').forEach((a)=>{
	    const subTags = a.innerHTML.split('/');
	    const tagName = subTags.pop();
	    a.innerHTML = '<span class="tag-sub-prefix">' + subTags.join('/') + '/</span>' + tagName;
	});
});

真是大神 :+1: :+1: 测试了可用。不过我想实现的是获取指定文件夹内的标签,该怎么弄呢?呈现方式希望是一行一个一个挨着排列,排满了自动换行,而不是一行一个那种

指定文件夹参考这里

名称排序不知是否指按前缀排序,可参考上面链接看看是否满足。

排序这类问题,ai最擅长,基本都能解决你的问题。

如果ai不能很好回答你的问题,可能你的提示词不够精确和全面。

建议看看这篇文章里的关于提示词优化部分 ChatGPT第三方推荐及省钱技巧

可以帮忙加一下,如果本页有的标签,就不在列表里显示吗?