[js 片段] 双击展开&展开全部_release_v1.0
功能介绍
- 双击节点展开/折叠 (DOUBLE_SWITCH 控制)
- 点击折叠按钮, 如果是从折叠到展开, 则自动展开所有子节点 (UNFOLD_ALL_SWITCH 控制)
/*
### [js片段] 双击展开&展开全部_release_v1.0
#### 功能介绍
1. 双击节点展开/折叠 (DOUBLE_SWITCH 控制)
2. 点击折叠按钮, 如果是从折叠到展开, 则自动展开所有子节点 (UNFOLD_ALL_SWITCH 控制)
*/
(() => {
/***************************自主配置begin**************************************/
// 修改配置后, 需要刷新页面(设置->快捷键->刷新), 否则会有问题
const CONFIG = {
DOUBLE_SWITCH : true, // 是否启用双击展开/折叠
DOUBLE_INTERVAL : 200, // 双击间隔时间 毫秒
UNFOLD_ALL_SWITCH : true, // 是否替换原始折叠按钮功能, 改为一键全部展开
UNFOLD_INTERVAL : 200, // 自动展开的点击的间隔, 如果你感觉展开很慢, 可适当调小
// 请注意 如果过于小, 可能会导致文档树渲染异常
};
/***************************自主配置end****************************************/
// 生成唯一ID用于日志标识
const SESSION_ID = Date.now();
// 点击类型枚举
const CLICK_TYPE = {
INVALID: 0, // 无效的点击
NODE : 1, // 点击节点
ARROW : 2, // 点击折叠按钮
BOOK : 3, // 点击笔记本
};
// 工具函数
const utils = {
log(...args) {
console.log(`[${SESSION_ID}]:`, ...args);
},
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},
getTagName(element) {
return element?.tagName?.toLowerCase() || '';
}
};
// 树节点处理类
class TreeHandler {
constructor() {
this.clickQueue = []; // 点击队列
this.isProcessing = false; // 是否正在处理队列
this.doubleClickFlag = false; // 双击标记
this.lastClickTime = 0; // 上次点击时间
}
// 获取当前元素对应的种类
getClickType(element) {
if (!element) return CLICK_TYPE.INVALID;
let target = element;
let tagName = utils.getTagName(target);
// 处理SVG元素
if (tagName === 'use') {
target = element.parentElement.parentElement;
} else if (tagName === 'svg') {
target = element.parentElement;
}
tagName = utils.getTagName(target);
if (tagName === 'ul') {
return CLICK_TYPE.INVALID;
}
else if (tagName === 'li' && target.getAttribute('data-path') === '/') {
return CLICK_TYPE.BOOK;
}
else if (tagName === 'li') {
return CLICK_TYPE.NODE;
}
else if (tagName === 'span') {
if (target.classList.contains('b3-list-item__toggle')) {
return CLICK_TYPE.ARROW;
}
else if (target.classList.contains('b3-list-item__text') &&
target.parentElement.getAttribute('data-path') === '/') {
return CLICK_TYPE.BOOK;
}
else if (target.classList.contains('b3-list-item__text')) {
return CLICK_TYPE.NODE;
}
}
return CLICK_TYPE.INVALID;
}
// 获取折叠按钮的span元素, 前提: element必须是折叠按钮
getArrowSpan(element) {
let target = element;
let tagName = utils.getTagName(target);
if (tagName === 'use') {
target = element.parentElement.parentElement;
} else if (tagName === 'svg') {
target = element.parentElement;
}
tagName = utils.getTagName(target);
if (tagName === 'span' && target.classList.contains('b3-list-item__toggle')) {
return target;
}
return null;
}
// 点击节点对应的折叠按钮, 前提: element必须是点击的节点
clickArrowButton(element) {
const li = utils.getTagName(element) === 'span' ?
element.parentElement : element;
if (utils.getTagName(li) !== 'li') return;
li.querySelector('span.b3-list-item__toggle:not(.fn__hidden)')?.click();
}
// 遍历 element下所有直接子节点的折叠按钮, 并点击
async unfoldChildNodes(element) {
const arrowSpan = this.getArrowSpan(element);
if (!arrowSpan) return;
if (!arrowSpan.querySelector('svg').classList.contains('b3-list-item__arrow--open')) {
return;
}
// 点击了折叠按钮, 且是展开的
utils.log("点击了折叠按钮, 且是展开的", arrowSpan);
const childNodes = Array.from(arrowSpan.parentElement.nextElementSibling.children);
childNodes.forEach(node => {
node.querySelector('span.b3-list-item__toggle:not(.fn__hidden)')?.click();
});
}
// 触发处理 点击队列
async processClickQueue() {
if (this.isProcessing) return;
this.isProcessing = true;
while (this.clickQueue.length) {
const action = this.clickQueue.shift();
await action();
}
this.isProcessing = false;
}
// 处理鼠标点击事件
handleClickEvent(event) {
const element = event.target;
const clickType = this.getClickType(element);
utils.log("点击了", clickType, element);
// 处理双击, 系统自带的双击监测事件, 有点问题, 所以自己实现一个
const currentTime = Date.now();
if (CONFIG.DOUBLE_SWITCH && currentTime - this.lastClickTime < CONFIG.DOUBLE_INTERVAL &&
clickType === CLICK_TYPE.NODE) {
utils.log("双击展开/折叠触发");
this.doubleClickFlag = true;
this.clickArrowButton(element);
}
this.lastClickTime = currentTime;
// 处理折叠按钮点击
if (CONFIG.UNFOLD_ALL_SWITCH && clickType === CLICK_TYPE.ARROW) {
if (this.doubleClickFlag) {
this.doubleClickFlag = false;
return;
}
utils.log("点击折叠按钮处理", element);
this.clickQueue.push(async () => {
await utils.sleep(CONFIG.UNFOLD_INTERVAL);
await this.unfoldChildNodes(element);
});
this.processClickQueue();
}
}
}
// 初始化并监听点击事件
let initInterval = setInterval(() => {
const treeContainer = document.querySelector('.sy__file>.fn__flex-1');
if (treeContainer) {
clearInterval(initInterval);
const handler = new TreeHandler();
treeContainer.addEventListener('click',
e => handler.handleClickEvent(e), true);
}
}, 200);
})();
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于