自己这块对于数据有一个特殊需求,根据不同的yaml属性分组汇总文件,方便自己根据属性,以及属性值快速筛选文件,正好摸鱼无聊,借助dataview试了一下,好像还不错
9 个赞
求分享代码。。。
1 个赞
求分享代码。。。
好厉害!!!支持
其实 dv.view()
默认会传 dv
,所以不用再自己的参数再传 dv
。
const { propertyTypesArg, folderArg } = input
dv.el(...) // 直接写就行
同样问题,不太会用
目录下的文件需要有对应的yaml标签
多谢解答,搞懂怎么用了
特别感谢,已经用上了,还用chatgpt修改了一下让它更好地自适应页面宽度
1 个赞
可以求个css吗,我怎么调也调不动,没法自适应页面宽度,尤其在手机上更窄了
1 个赞
我改了一个合适的css,原理是变成了弹性布局,自动按比例分配空间
而且增加了一个button,可以在匹配文件夹新建一个具有相应yaml的文件
这里是代码
// 主视图函数,接收配置参数对象
function mainView({dvOpArg, propertyTypesArg, folderArg}) {
const dvOp = dvOpArg; // 获取Dataview API操作对象
const folder = folderArg; // 获取要查询的目标文件夹路径
const propertyTypes = [ // 创建属性类型数组的副本(避免修改原始数据)
...propertyTypesArg // 使用展开运算符进行浅拷贝
];
// 创建顶层容器
const container = dvOp.el("div", "", {
attr: { style: "display: flex; flex-direction: column; gap: 10px;" }
});
// 新建按钮容器(单独放在最上方)
const headerContainer = dvOp.el("div", "", {
container,
attr: { style: "margin-bottom: 5px;" }
});
// 添加新建按钮
const newButton = dvOp.el("button", "新建+", {
container: headerContainer,
attr: {
style: `
background-color: var(--interactive-accent);
color: white;
padding: 5px 15px;
Margin-left:25px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;`
}
});
// 新建按钮点击事件
newButton.addEventListener("click", async (evt) => {
evt.preventDefault();
// 生成Frontmatter
const frontmatter = propertyTypesArg.map(prop => {
const defaultValue = prop.type === "list" ? "[]" : '""';
return `${prop.code}: ${defaultValue}`;
}).join("\n");
// 创建文件名
const timestamp = new Date().getTime();
const fileName = `新建笔记-${timestamp}.md`;
try {
// 创建文件
const newFile = await dv.app.vault.create(
`${folder}/${fileName}`,
`---\n${frontmatter}\n---\n`
);
// 在新标签页打开
dv.app.workspace.openLinkText(newFile.basename, newFile.path, true, { active: false });
} catch (error) {
console.error("创建文件失败:", error);
dvOp.el("div", "创建文件失败,请检查控制台", { container: headerContainer });
}
});
// 创建三栏容器
const listRoot = dvOp.el("div", "", {
container,
cls: "listRoot",
attr: {style: `
display: flex;
height: 505px;
gap: 15px;
box-sizing: border-box;`}
});
// 左侧属性类型选择栏(1份)----------------------------------------
const mainRoot = dvOp.el(
"div",
"",
{
container: listRoot, // 指定父容器
cls: "leftRoot", // CSS类名
attr: {
style: `
height: 500px; /* 高度略小于父容器避免滚动条溢出 */
overflow: scroll; /* 内容溢出时显示滚动条 */
padding: 5px; /* 内边距 */
flex: 0.6; /* 占据1份弹性空间 */`
}
}
);
// 创建属性类型按钮列表---------------------------------------------
propertyTypes.forEach(item => { // 遍历每个属性类型
item.btn = dvOp.el( // 创建按钮元素并保存到item对象
"li", // 列表项元素
dvOp.el("button", item.name), // 嵌套创建按钮元素
{
container: mainRoot, // 指定父容器
attr: {
style: "margin: 3px" // 按钮间距样式
}
}
)
})
// 中间属性值列表栏(1份)------------------------------------------
const leftRoot = dvOp.el(
"div",
"",
{
container: listRoot, // 指定父容器
cls: "leftRoot", // CSS类名
attr: {
style: `
height: 500px;
overflow: scroll;
padding: 5px;
flex: 1.4; /* 占据1份弹性空间 */`
}
}
);
// 右侧详情展示栏(3份)-------------------------------------------
const rightRoot = dvOp.el(
"div",
"",
{
container: listRoot, // 指定父容器
cls: "rightRoot", // CSS类名
attr: {
style: `
height: 500px;
overflow: scroll;
padding: 5px;
flex: 3; /* 占据3份弹性空间 */`
}
}
);
// 状态管理变量---------------------------------------------------
let isInit = true; // 初始化标记,用于首次加载时自动触发数据加载
// 数据展示函数---------------------------------------------------
function showData(a, code, type) {
// 参数说明:
// a - 选中的属性值
// code - 属性类型代码
// type - 属性值类型(list/single)
rightRoot.replaceChildren(); // 清空右侧栏内容
if (a && a !== "") { // 有效值检查
dvOp.pages(`"${folder}"`) // 查询指定文件夹的页面
.where(t => // 过滤条件
type === "list" ? // 根据属性类型选择过滤方式
t[code]?.includes(a) : // 列表属性:检查是否包含
t[code] === a // 单值属性:精确匹配
)
.map(k => k.file.link) // 提取文件链接
.forEach(item => { // 遍历结果
dvOp.el( // 创建列表项
"li",
item,
{
container: rightRoot,
attr: {style: "margin: 5px"}
}
);
});
}
}
// 事件绑定逻辑---------------------------------------------------
propertyTypes.forEach(typeItem => { // 遍历每个属性类型
typeItem.btn.addEventListener( // 为按钮添加点击事件监听
"click",
async (evt) => { // 异步事件处理函数
evt.preventDefault(); // 阻止默认行为
leftRoot.replaceChildren(); // 清空中间栏
rightRoot.replaceChildren(); // 清空右侧栏
const typeMap = []; // 创建类型统计数组
// 数据统计逻辑--------------------------------------------
if (typeItem.type === 'list') { // 处理列表类型属性
for (const item of dvOp.pages(`"${folder}"`)) { // 遍历所有页面
if (item[typeItem.code]?.length > 0) { // 检查有效属性
for (const it of item[typeItem.code]) { // 遍历属性值列表
const typeObj = typeMap.findIndex( // 查找已有统计项
value => value.name === it
);
if (typeObj > -1) {
typeMap[typeObj].count += 1; // 计数增加
} else {
typeMap.push({ // 新建统计项
name: it,
count: 1
});
}
}
}
}
} else { // 处理单值类型属性
for (const item of dvOp.pages(`"${folder}"`)) {
if (item[typeItem.code]) { // 检查有效属性
const it = item[typeItem.code];
const typeObj = typeMap.findIndex(
value => value.name === it
);
if (typeObj > -1) {
typeMap[typeObj].count += 1;
} else {
typeMap.push({
name: it,
count: 1
});
}
}
}
}
// 渲染中间栏列表------------------------------------------
for (const item of typeMap) { // 遍历统计结果
const li = dvOp.el( // 创建列表项
"li",
"",
{
container: leftRoot,
attr: {style: "margin: 5px"}
}
);
const button = dvOp.el( // 创建带计数的按钮
"button",
`${item.name}(${item.count})`,
{ container: li }
);
button.addEventListener("click", // 按钮点击事件
async (evt) => {
evt.preventDefault();
showData(item.name, typeItem.code, typeItem.type);
}
);
// 自动触发首次点击--------------------------------------
if (isInit) { // 检查初始化标记
button.click(); // 模拟点击
isInit = false; // 标记已初始化
}
}
}
);
})
// 初始化触发第一个属性类型的点击----------------------------------
propertyTypes[0].btn.click();
}
// 执行主函数-------------------------------------------------------
mainView(input);
1 个赞
你好,感谢你的CSS代码,我把这个代码用以下方式使用:
但是不知道为什么,好像前后没啥效果,中间还是有大段的空白,没有紧凑(第一个为未使用CSS,第二个为使用CSS):
是我的使用方法有问题吗?还是哪里出问题了吗?
1 个赞
用法是直接替换原来的js文件(删去原来的),我是在dataviewjs代码中修改了css
1 个赞