求 js 代码,只展开当前活动页签的文档树

求 js 代码,在使用“始终定位打开的文档”功能时,只展开当前文档的文档树,自动关闭(不展开)其它无关的文档树。例如:

有笔记本 A,内有文档 A1,子文档 A2、子子文档 A3。

有笔记本 B,内有文档 B1,子文档 B2、子子文档 B3。

已将文档 A2、B2 打开,显示在上方页签栏中。

启用“始终定位打开的文档”功能。

点击 A2 页签,左侧文档树自动展开,并定位到 A-A1-A2;A3 列表不展开

点击 B2 页签,左侧文档树自动展开,定位到 B-B1-B2;同时关闭 A-A1-A2 文档树的展开状态,恢复到笔记本 A。也就是仅保留当前活动页签对应的文档树是展开状态,其它文档树分支全部关闭,包括当前活动文档的子文档树。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22346 引用 • 89411 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    8116 引用 • 37016 回帖 • 160 关注
1 操作
wenbocn 在 2024-06-02 13:54:35 更新了该帖

相关帖子

被采纳的回答
  • wilsons 1

    时隔 1 个多月,你解决了吗?相见即是有缘,看到此贴感觉有些思路,就尝试写了下,实现了这个功能。由于刚接触思源,对思源 api 还不是很了解,所以选择用 js 代码片段实现,纯原生 js 实现,方法比较笨,勉强能用。

    不足之处也请论坛里的大佬们多多批评指正!

    效果如下:

    t2.gif

    完整代码如下:

    // 等待标签页容器渲染完成后开始监听
    whenElementExist('.layout__center').then(async element => {
        // 等待笔记列表加载完毕
        await sleep(40);
        // 监听页签切换事件
        observeTabChanged(element, (tab) => {
            // 折叠所有笔记,然后定位当前笔记
            collapseAllBooksThenFocusCurrentBook(element, tab);
        });
    });
    // 折叠所有笔记,然后定位当前笔记
    async function collapseAllBooksThenFocusCurrentBook(element, tab) {
        // 等待激活文档加载完毕
        await whenElementExist(()=>{
            const content = element.querySelector('.layout-tab-container [data-id="'+tab.getAttribute("data-id")+'"]');
            return content && content.getAttribute("data-loading") === "finished";
        });
        // 折叠所有笔记
        document.querySelectorAll("ul.b3-list[data-url]").forEach(async book => {
            const bookName = tab.getAttribute("aria-label")?.split('/')[0];
            if(bookName) {
                // 如果在本笔记中则不再折叠
                const bookText = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
                if(bookText === bookName) {
                    return;
                }
            }
            // 折叠笔记
            const bookArrowBtn = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__toggle');
            if (bookArrowBtn && bookArrowBtn.firstElementChild.classList.contains("b3-list-item__arrow--open")) {
                bookArrowBtn.click();
            }
        });
        // 定位当前笔记
        document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    }
    // 监听页签切换事件
    function observeTabChanged(parentNode, callback) {
        // 创建一个回调函数来处理观察到的变化
        const observerCallback = function(mutationsList, observer) {
            // 用常规方式遍历 mutationsList 中的每一个 mutation
            for (let mutation of mutationsList) {
                // 属性被修改
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    const element = mutation.target;
                    if (element.tagName.toLowerCase() === 'li' && element.getAttribute('data-type') === 'tab-header' && element.classList.contains('item--focus')) {
                        if(typeof callback === 'function') callback(element);
                    }
                }
                // 如果有新的子节点被添加
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'li') {
                            if (node.getAttribute('data-type') === 'tab-header' && node.classList.contains('item--focus')) {
                                if(typeof callback === 'function') callback(node);
                            }
                        }
                    });
                }
            }
        };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(observerCallback);
        // 配置观察器:传递一个对象来指定观察器的行为
        const config = { attributes: true, attributeFilter: ['class'], childList: true, subtree: true };
        // 开始观察目标节点
        observer.observe(parentNode, config);
        // 返回一个函数,用于停止观察
        return function stopObserving() {
            observer.disconnect();
        };
    }
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // 等待元素渲染完成后执行
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                let element = null;
                if (typeof selector === 'function') {
                    element = selector();
                } else {
                    element = document.querySelector(selector);
                }
                if (element) {
                    resolve(element);
                } else {
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    

    使用方法:

    设置 》外观 》代码片段 》js 中新增加代码片段,然后把上面的代码粘贴过去即可。

    image.png

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • wenbocn

    其实使用 Ctrl+↑(文档树折叠快捷键),再点击“定位当前打开的文档”按钮,就能完美实现想要的效果。不过会使步骤繁琐,供参考。

  • 其他回帖
  • wilsons 1

    时隔 1 个多月,你解决了吗?相见即是有缘,看到此贴感觉有些思路,就尝试写了下,实现了这个功能。由于刚接触思源,对思源 api 还不是很了解,所以选择用 js 代码片段实现,纯原生 js 实现,方法比较笨,勉强能用。

    不足之处也请论坛里的大佬们多多批评指正!

    效果如下:

    t2.gif

    完整代码如下:

    // 等待标签页容器渲染完成后开始监听
    whenElementExist('.layout__center').then(async element => {
        // 等待笔记列表加载完毕
        await sleep(40);
        // 监听页签切换事件
        observeTabChanged(element, (tab) => {
            // 折叠所有笔记,然后定位当前笔记
            collapseAllBooksThenFocusCurrentBook(element, tab);
        });
    });
    // 折叠所有笔记,然后定位当前笔记
    async function collapseAllBooksThenFocusCurrentBook(element, tab) {
        // 等待激活文档加载完毕
        await whenElementExist(()=>{
            const content = element.querySelector('.layout-tab-container [data-id="'+tab.getAttribute("data-id")+'"]');
            return content && content.getAttribute("data-loading") === "finished";
        });
        // 折叠所有笔记
        document.querySelectorAll("ul.b3-list[data-url]").forEach(async book => {
            const bookName = tab.getAttribute("aria-label")?.split('/')[0];
            if(bookName) {
                // 如果在本笔记中则不再折叠
                const bookText = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
                if(bookText === bookName) {
                    return;
                }
            }
            // 折叠笔记
            const bookArrowBtn = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__toggle');
            if (bookArrowBtn && bookArrowBtn.firstElementChild.classList.contains("b3-list-item__arrow--open")) {
                bookArrowBtn.click();
            }
        });
        // 定位当前笔记
        document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    }
    // 监听页签切换事件
    function observeTabChanged(parentNode, callback) {
        // 创建一个回调函数来处理观察到的变化
        const observerCallback = function(mutationsList, observer) {
            // 用常规方式遍历 mutationsList 中的每一个 mutation
            for (let mutation of mutationsList) {
                // 属性被修改
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    const element = mutation.target;
                    if (element.tagName.toLowerCase() === 'li' && element.getAttribute('data-type') === 'tab-header' && element.classList.contains('item--focus')) {
                        if(typeof callback === 'function') callback(element);
                    }
                }
                // 如果有新的子节点被添加
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'li') {
                            if (node.getAttribute('data-type') === 'tab-header' && node.classList.contains('item--focus')) {
                                if(typeof callback === 'function') callback(node);
                            }
                        }
                    });
                }
            }
        };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(observerCallback);
        // 配置观察器:传递一个对象来指定观察器的行为
        const config = { attributes: true, attributeFilter: ['class'], childList: true, subtree: true };
        // 开始观察目标节点
        observer.observe(parentNode, config);
        // 返回一个函数,用于停止观察
        return function stopObserving() {
            observer.disconnect();
        };
    }
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // 等待元素渲染完成后执行
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                let element = null;
                if (typeof selector === 'function') {
                    element = selector();
                } else {
                    element = document.querySelector(selector);
                }
                if (element) {
                    resolve(element);
                } else {
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    

    使用方法:

    设置 》外观 》代码片段 》js 中新增加代码片段,然后把上面的代码粘贴过去即可。

    image.png

    4 回复
  • wenbocn

    好像是我自己的某个 css 导致的个例问题,不是该 js 代码导致的问题。

  • player 1 赞同

    ToolbarBox

    这里有除了自动定位的其他代码。 自动定位就做个监听, 针对 class layout__wnd--active ,发现有 tab 的变化,就触发一次,locateDoc() 即可。

    1 回复
  • 查看全部回帖

推荐标签 标签

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1327 回帖
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 611 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    90 引用 • 899 回帖
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 399 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 664 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    8 引用 • 30 回帖 • 407 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖 • 1 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 303 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    130 引用 • 793 回帖
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 1 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    52 引用 • 190 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 742 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    180 引用 • 400 回帖
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    198 引用 • 550 回帖
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 6 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    15 引用 • 122 回帖
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    59 引用 • 29 回帖 • 5 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 211 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 53 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 62 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • 音乐

    你听到信仰的声音了么?

    60 引用 • 511 回帖
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    169 引用 • 506 回帖