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

本贴最后更新于 319 天前,其中的信息可能已经时移俗易

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

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

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

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

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

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

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

  • 思源笔记

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

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

    25117 引用 • 103552 回帖 • 1 关注
  • Q&A

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

    9581 引用 • 43583 回帖 • 97 关注
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

优质回帖
  • wilsons 2

    @wenbocn 我已完美实现了不闪动的版本,并且改进了官方定位,在未打开目录树时,左侧 dock 区目录树显示隐藏按钮样式会获取焦点的 bug

    效果如下

    t6.gif

    完整代码如下

    由于链滴代码长度有限制,只能放到 jsrun 了。

  • wilsons 2

    确实是焦点问题,楼主主要想要的是定位文档树,且定位和展开关闭目录使用了模拟点击,这些操作都会使当前文档的焦点移动到目录树上,导致大纲还没来得及切换就失去焦点文档了。

    其实,定位文档树也是要获得焦点的,这和文档焦点矛盾,具体怎么做看自己需求,是希望最后焦点落在哪里?

    如果想最终焦点落在文档树上,可以在 focusCurrentDocInTrees 函数的开头加上 sleep(120),等待大纲切换完毕再定位

    image.png

    image.png

    如果想最终焦点落在文档上,则在 focusCurrentDocInTrees 函数的末尾加上以下代码,定位文档树后恢复文档焦点

    // 文档树模拟点击后恢复文档窗口(编辑器)的焦点(最终焦点在文档) whenElementExist('.layout__tab--active .b3-list--background .b3-list-item--focus').then(() => { const activepPotyle = document.querySelector('[data-type="wnd"].layout__wnd--active .protyle:not(.fn__none)')||document.querySelector('[data-type="wnd"] .protyle:not(.fn__none)'); if(activepPotyle) activepPotyle.click(); });

    image.png

    image.png

    这是我修改后的代码,只需要配置这个参数即可

    // 最终焦点落在文档树还是文档上? tree 文档树,doc 文档
    const lastFoucsIn = 'doc';

    https://gitee.com/wish163/mysoft/blob/main/%E6%80%9D%E6%BA%90/%E5%8F%AA%E5%B1%95%E5%BC%80%E5%BD%93%E5%89%8D%E6%B4%BB%E5%8A%A8%E9%A1%B5%E7%AD%BE%E7%9A%84%E6%96%87%E6%A1%A3%E6%A0%91.js

  • player 1 赞同

    ToolbarBox

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

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • JeffreyChen 1 1 评论

    在这里会显示最近有回帖的帖子:https://ld246.com/recent/reply

    原来如此
    wilsons
  • 其他回帖
  • wenbocn

    使用 ChatGPT 修改了代码,点击文档树,不会有跳动现象了。但点击标签页及正文后的输入焦点在文档内,能够正常编辑文档,但显示焦点却在文档树的按钮上,不知咋回事。

    // 等待元素渲染完成后执行 function whenElementExist(selector) { return new Promise(resolve => { const checkForElement = () => { const element = typeof selector === 'function' ? selector() : document.querySelector(selector); if (element) { resolve(element); } else { requestAnimationFrame(checkForElement); } }; checkForElement(); }); } // 延迟执行 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 折叠所有笔记,然后定位当前笔记 async function collapseAllBooksThenFocusCurrentBook(tab) { const currentBookName = tab.getAttribute("aria-label")?.split('/')[0]; // 等待文档加载完毕 await whenElementExist(() => { const content = document.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(book => { const bookName = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText; if (bookName !== currentBookName) { 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(callback) { const observerCallback = (mutationsList) => { mutationsList.forEach(mutation => { if ((mutation.type === 'attributes' && mutation.attributeName === 'class') || (mutation.type === 'childList' && mutation.addedNodes.length > 0)) { const focusedTab = mutation.target.closest('li[data-type="tab-header"].item--focus'); if (focusedTab) callback(focusedTab); } }); }; const observer = new MutationObserver(observerCallback); observer.observe(document.querySelector('.layout__center'), { attributes: true, childList: true, subtree: true }); return () => observer.disconnect(); } // 主函数,等待容器渲染后开始监听 whenElementExist('.layout__center').then(async () => { await sleep(40); observeTabChanged(collapseAllBooksThenFocusCurrentBook); });
    1 回复
  • 发了 https://sypai.cc/archives/977/

    @wenbocn 从代码中提取的这段代码,本意是想通过标签的 aria-label 属性实现,如果展开的笔记是当前点击的文档所在笔记不再折叠再展开了,这样防止出现跳动。但现在想来如果同一个笔记下,展开多个目录可能会导致同个笔记下的文档切换时不再折叠,不知道是否符合你的需求,如果不符合,建议把这段代码删除。而且这段代码在打开文档时还会出现跳动,实现并不完美。

    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; } }

    比如,如下场景不会折叠同个笔记下的目录

    t4.gif

    2 回复
  • wilsons 2

    确实是焦点问题,楼主主要想要的是定位文档树,且定位和展开关闭目录使用了模拟点击,这些操作都会使当前文档的焦点移动到目录树上,导致大纲还没来得及切换就失去焦点文档了。

    其实,定位文档树也是要获得焦点的,这和文档焦点矛盾,具体怎么做看自己需求,是希望最后焦点落在哪里?

    如果想最终焦点落在文档树上,可以在 focusCurrentDocInTrees 函数的开头加上 sleep(120),等待大纲切换完毕再定位

    image.png

    image.png

    如果想最终焦点落在文档上,则在 focusCurrentDocInTrees 函数的末尾加上以下代码,定位文档树后恢复文档焦点

    // 文档树模拟点击后恢复文档窗口(编辑器)的焦点(最终焦点在文档) whenElementExist('.layout__tab--active .b3-list--background .b3-list-item--focus').then(() => { const activepPotyle = document.querySelector('[data-type="wnd"].layout__wnd--active .protyle:not(.fn__none)')||document.querySelector('[data-type="wnd"] .protyle:not(.fn__none)'); if(activepPotyle) activepPotyle.click(); });

    image.png

    image.png

    这是我修改后的代码,只需要配置这个参数即可

    // 最终焦点落在文档树还是文档上? tree 文档树,doc 文档
    const lastFoucsIn = 'doc';

    https://gitee.com/wish163/mysoft/blob/main/%E6%80%9D%E6%BA%90/%E5%8F%AA%E5%B1%95%E5%BC%80%E5%BD%93%E5%89%8D%E6%B4%BB%E5%8A%A8%E9%A1%B5%E7%AD%BE%E7%9A%84%E6%96%87%E6%A1%A3%E6%A0%91.js

    2 回复
    1 操作
    wilsons 在 2025-03-14 20:25:34 更新了该回帖
  • 查看全部回帖

推荐标签 标签

  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 608 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖 • 2 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 4 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 79 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    367 引用 • 1842 回帖
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    57 引用 • 25 回帖 • 2 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    107 引用 • 127 回帖 • 343 关注
  • OpenCV
    15 引用 • 36 回帖 • 1 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 341 关注
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • V2Ray
    1 引用 • 15 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 119 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 3 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 545 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 554 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 653 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 133 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    31 引用 • 108 回帖 • 1 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1454 回帖
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖 • 10 关注
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    99 引用 • 367 回帖 • 1 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1057 回帖 • 1 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 2 关注
  • 大数据

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

    93 引用 • 113 回帖
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖