[JS] 添加复选框按钮简单运行一些菜单项, 复制正文文字内容

移动安卓端的有些功能藏在菜单里,要划来划去.

就抄了个 js 代码片段放在页面两边,点击弹出对应菜单(太懒了).

不会 js,只能照板煮碗.

本来想抄个按钮代码的,不会改 >_<.

如果用 ai,估计能唰唰就完成了,可惜也不会.

20250316 更新:

一,PC 端在顶栏添加两个按钮,

一个是重载页面.

一个是半成品的复制正文文字内容.

由于个人能力问题,复制正文内容有以下缺点:

1.不知道怎样定位之前打开的页面,只能复制最新打开的页面.如果想复制已打开的页面,请关闭它再重新打开.

2.复制的正文文字内容只能复制已加载的部分,太长的内容由于懒加载原因而未加载的部分请手动加载后再复制.

二,安卓端其中一个按钮也更改为半成品的复制正文文字内容


原代码:

[js] [仅适用于手机端] 一个在锁定编辑旁边可以隐藏一些图标的 js


相关注意项:


1.右边复选框开关我点击的菜单是右边的菜单第一层,

可以自行修改为想运行的代码或相关菜单的 id.

如:#plugin_siyuan-plugins-index_0


2.左边复选框开关我点击的是左边顶层工具栏的插件工具栏里面的一项.

找不到菜单第一层和第二层的 id 和类名,只好用最粗旷的模拟点击.

这个就和主题的按钮大小相关了.

默认主题按钮大概是 43px,

所以插件工具栏(第七个)的 Y 坐标取 280.

43*6=258, 43*7=301

需要修改为你自己想点击的菜单的坐标.

当然,各位大佬直接修改为想运行的代码更直接.


3.坐标也可以用这个小代码来获取.

打开思源浏览器安卓端,按下 F12,在控制台粘贴以下代码,按 Enter

然后点击网页你想点击的地方,就可以得到坐标, ID(如果有)和类名(如果有).

document.addEventListener('click', (e) => { console.log(e.target); // 获取点击的坐标 const x = e.clientX; const y = e.clientY; // 输出坐标 console.log(`坐标: (${x}, ${y})`); });

4.左边工具栏第二层菜单生成需要时间,我添加了延时,默认 1500.

你可以根据自己手机性能来调整大小.

第三次点击是根据菜单名字搜索的,

这条代码由 JeffreyChen 大大 请问类名相同, 如何根据文本内容获取元素, 谢谢. 提供,谢谢.

var button003 = Array.from(document.querySelectorAll('span.b3-menu__label')).find(label => label.textContent.includes('基于文档搜索 Dock'));

可以修改自己想点击的菜单名字

如"基于文档搜索 Dock"


5.上面 1,2,4 点在代码里面都有注释.


PC 端复制正文文字内容录屏 gif:

screenshots.gif


浏览器移动端录屏 gif:

移动端弹出菜单复制正文.gif




20250316 新版代码:


// 插入开关功能 function insertSwitchBeforeButton() { // 循环查找目标按钮,直到找到为止 function findAndInsert() { // 尝试查找目标按钮,仅在符合指定选择器时插入 let barforward_desktop = document.querySelector("#barForward"); let drag_desktop = document.querySelector("#drag"); let spacebar_mobile = document.querySelector('#editor > div.protyle-breadcrumb > span.protyle-breadcrumb__space'); let unlock_mobile = document.querySelector('#editor > div.protyle-breadcrumb > button.protyle-breadcrumb__icon.ariaLabel'); let toolbar = document.querySelector('.toolbar.toolbar--border'); // 查找需要控制的工具栏 let css1 = document.querySelector('#editor > div.protyle-content.protyle-content--transition > div.protyle-top'); if ( barforward_desktop || spacebar_mobile ) { // 如果找到了目标按钮和工具栏,且符合选择器 let switchElement_desktop01 = document.createElement('input'); switchElement_desktop01.type = 'checkbox'; // 创建一个复选框作为开关 switchElement_desktop01.style.marginRight = '8px'; // 添加样式,调整位置 switchElement_desktop01.checked = false; // 默认是未选中状态,工具栏显示 let switchElement_desktop02 = document.createElement('input'); switchElement_desktop02.type = 'checkbox'; // 创建一个复选框作为开关01 switchElement_desktop02.style.marginLeft = '8px'; // 添加样式,调整位置 switchElement_desktop02.checked = false; // 默认是未选中状态,工具栏显示 let switchElement_mobile01 = document.createElement('input'); switchElement_mobile01.type = 'checkbox'; // 创建一个复选框作为开关 switchElement_mobile01.style.marginRight = '8px'; // 添加样式,调整位置 switchElement_mobile01.checked = false; // 默认是未选中状态,工具栏显示 let switchElement_mobile02 = document.createElement('input'); switchElement_mobile02.type = 'checkbox'; // 创建一个复选框作为开关01 switchElement_mobile02.style.marginLeft = '8px'; // 添加样式,调整位置 switchElement_mobile02.checked = false; // 默认是未选中状态,工具栏显示 // 桌面端开关01的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement_desktop01.addEventListener('change', () => { if (switchElement_desktop01.checked) { //下面可以修改为想运行的代码 copyAreaContent(); //上面是想运行的代码 setTimeout(() => { switchElement_desktop01.checked = false; }, 500); } }); // 桌面端开关02的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement_desktop02.addEventListener('change', () => { if (switchElement_desktop02.checked) { //下面可以修改为想运行的代码 refresh01(); //上面是想运行的代码 setTimeout(() => { switchElement_desktop02.checked = false; }, 500); } }); // 移动端开关01的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement_mobile01.addEventListener('change', () => { if (switchElement_mobile01.checked) { //下面可以修改为想运行的代码 copyAreaContent(); //上面是想运行的代码 setTimeout(() => { switchElement_mobile01.checked = false; }, 500); } }); // 移动端开关02的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement_mobile02.addEventListener('change', () => { if (switchElement_mobile02.checked) { //下面可以修改为想运行的代码 small_notes_sidebar(); //上面是想运行的代码 setTimeout(() => { switchElement_mobile02.checked = false; }, 500); } }); // 插入开关到按钮前面 if (barforward_desktop) { // 桌面端 barforward_desktop.parentNode.insertBefore(switchElement_desktop01, drag_desktop); console.log("桌面端开关01已成功插入到目标按钮前面"); barforward_desktop.parentNode.insertBefore(switchElement_desktop02, barforward_desktop); console.log("桌面端开关02已成功插入到目标按钮前面"); } else { // 移动端 spacebar_mobile.parentNode.insertBefore(switchElement_mobile01, unlock_mobile); console.log("移动端开关01已成功插入到目标按钮前面"); spacebar_mobile.parentNode.insertBefore(switchElement_mobile02, spacebar_mobile); console.log("移动端开关02已成功插入到目标按钮前面"); } // 停止查找 clearInterval(searchInterval); } else { console.warn("目标按钮或工具栏未找到,继续尝试..."); } } // 每隔 1000 毫秒查找一次目标按钮和工具栏 let searchInterval = setInterval(findAndInsert, 1000); // 如果超过 10 秒仍未找到,停止查找并提示 setTimeout(() => { clearInterval(searchInterval); console.error("超过 2 秒仍未找到目标按钮或工具栏,请检查选择器或页面是否正确加载"); }, 2000); // 2 秒后停止查找 } // 启动插入开关功能 insertSwitchBeforeButton(); //以下是点击按钮实现的4个效果 //效果1,重置刷新页面 function refresh01() { //重置刷新页面 window.location.reload(); } //效果2,小记弹出新建窗口(安卓端) function small_notes() { 这里是点击右边的顶层菜单项 window.location.reload(); //这个是重置页面 获取元素 let button001 = document.querySelector('#plugin_quick-notes_0'); 触发点击事件 button001.click(); console.log("小记弹出新建窗口成功"); } //效果3,显示小记侧边栏(安卓端) function small_notes_sidebar() { //这里是运行左边顶部工具栏插件按钮第二层的显示侧边栏 //第二次点击的坐标x2,y2要根据主题来修改 // 定义我们要点击的坐标1 const x1 = 10; const y1 = 10; // 获取指定坐标上的元素 const el = document.elementFromPoint(x1, y1); const click01 = (x1, y1) => { const ev = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': true, 'screenX': x1, 'screenY': y1 }); // 分发点击事件 el.dispatchEvent(ev); }; // 调用点击函数 click01(x1, y1); console.log(el); setTimeout(() => { // 定义我们要点击的坐标2 const x2 = 260; //默认主题顶部工具栏插件按钮的坐标为280 const y2 = 20; // 获取指定坐标上的元素 const e2 = document.elementFromPoint(x2, y2); const click02 = (x2, y2) => { const ev = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': true, 'screenX': x2, 'screenY': y2 }); // 分发点击事件 e2.dispatchEvent(ev); }; // 调用点击函数 click02(x2, y2); console.log(e2); }, 500); setTimeout(() => { var button003 = Array.from(document.querySelectorAll('span.b3-menu__label')).find(label => label.textContent.includes('显示小记侧边栏')); button003.click(); console.log("小记侧边栏已显示"); }, 1500); //这里的延迟时间看手机性能,性能不够的可以调大一些 } //效果4,半成品复制正文文字 function copyAreaContent() { // 1. 获取目标元素 let targetElement_mobile = document.querySelector('#editor > div.protyle-content.protyle-content--transition > div.protyle-wysiwyg.protyle-wysiwyg--attr'); let targetElement_desktop = Array.from(document.getElementsByClassName('protyle-wysiwyg--attr')); let i001 = targetElement_desktop.length-1; let targetElement = (targetElement_desktop[i001] || targetElement_mobile); // 2. 创建选区(Range) const range = document.createRange(); range.selectNodeContents(targetElement); // 3. 将选区添加到 Selection 对象 const selection = window.getSelection(); selection.removeAllRanges(); // 清除现有选区 selection.addRange(range); try { // 4. 复制内容到剪贴板(现代浏览器推荐 Clipboard API) //if (navigator.clipboard) { let textArea = document.createElement("textarea"); str01 = selection.toString().replace(//g,""); textArea.value = str01; // 使text area不在viewport,同时设置不可见 textArea.style.position = "absolute"; textArea.style.opacity = 0; textArea.style.left = "-999999px"; textArea.style.top = "-999999px"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); return new Promise((res, rej) => { // 执行复制命令并移除文本框 document.execCommand('copy') ? res() : rej(); textArea.remove(); console.log("内容已复制"); }); //} else { // // 旧浏览器回退到 execCommand // document.execCommand("copy"); // console.log("内容已复制(旧浏览器方式)"); //} } catch (err) { console.error("复制失败:", err); } // 5. 清除选区(可选) selection.removeAllRanges(); }

旧版代码:


// 插入开关功能 function insertSwitchBeforeButton() { // 循环查找目标按钮,直到找到为止 function findAndInsert() { // 尝试查找目标按钮,仅在符合指定选择器时插入 let targetButton = document.querySelector('#editor > div.protyle-breadcrumb > button.protyle-breadcrumb__icon.ariaLabel'); let targetButton01 = document.querySelector('#editor > div.protyle-breadcrumb > span.protyle-breadcrumb__space'); let toolbar = document.querySelector('.toolbar.toolbar--border'); // 查找需要控制的工具栏 let css1 = document.querySelector('#editor > div.protyle-content.protyle-content--transition > div.protyle-top'); if (targetButton && toolbar) { // 如果找到了目标按钮和工具栏,且符合选择器 let switchElement = document.createElement('input'); switchElement.type = 'checkbox'; // 创建一个复选框作为开关 switchElement.style.marginRight = '8px'; // 添加样式,调整位置 switchElement.checked = false; // 默认是未选中状态,工具栏显示 let switchElement01 = document.createElement('input'); switchElement01.type = 'checkbox'; // 创建一个复选框作为开关01 switchElement01.style.marginLeft = '8px'; // 添加样式,调整位置 switchElement01.checked = false; // 默认是未选中状态,工具栏显示 // 开关的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement.addEventListener('change', () => { if (switchElement.checked) { //下面可以修改为想运行的代码 //这里是点击右边的顶层菜单项 //window.location.reload(); //这个是重置页面 // 获取元素 let button001 = document.querySelector('#plugin_siyuan-plugins-index_0');//修改为想点击的菜单id // 触发点击事件 button001.click(); //上面是想运行的代码 switchElement.checked = false; console.log("文档目录已更新"); } }); // 开关01的点击事件,用来控制工具栏和按钮的显示和隐藏 switchElement01.addEventListener('change', () => { if (switchElement01.checked) { //下面可以修改为想运行的代码 //这里是运行左边顶部工具栏插件按钮第二层的显示侧边栏 //第二次点击的坐标x2,y2要根据主题来修改 // 定义我们要点击的坐标1 const x1 = 10; const y1 = 10; // 获取指定坐标上的元素 const el = document.elementFromPoint(x1, y1); const click01 = (x1, y1) => { const ev = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': true, 'screenX': x1, 'screenY': y1 }); // 分发点击事件 el.dispatchEvent(ev); }; // 调用点击函数 click01(x1, y1); console.log(el); setTimeout(() => { // 定义我们要点击的坐标2 const x2 = 280; //默认主题顶部工具栏插件按钮的坐标为280 const y2 = 20; // 获取指定坐标上的元素 const e2 = document.elementFromPoint(x2, y2); const click02 = (x2, y2) => { const ev = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': true, 'screenX': x2, 'screenY': y2 }); // 分发点击事件 e2.dispatchEvent(ev); }; // 调用点击函数 click02(x2, y2); console.log(e2); }, 500); setTimeout(() => { var button003 = Array.from(document.querySelectorAll('span.b3-menu__label')).find(label => label.textContent.includes('基于文档搜索 Dock')); button003.click(); }, 1500); //这里的延迟时间看手机性能,性能不够的可以调大一些 //上面是想运行的代码 switchElement01.checked = false; console.log("文档搜索"); } }); // 插入开关到按钮前面 targetButton.parentNode.insertBefore(switchElement, targetButton); console.log("开关已成功插入到目标按钮前面"); targetButton01.parentNode.insertBefore(switchElement01, targetButton01); console.log("开关01已成功插入到目标按钮前面"); // 停止查找 clearInterval(searchInterval); } else { console.warn("目标按钮或工具栏未找到,继续尝试..."); } } // 每隔 1000 毫秒查找一次目标按钮和工具栏 let searchInterval = setInterval(findAndInsert, 1000); // 如果超过 10 秒仍未找到,停止查找并提示 setTimeout(() => { clearInterval(searchInterval); console.error("超过 2 秒仍未找到目标按钮或工具栏,请检查选择器或页面是否正确加载"); }, 2000); // 2 秒后停止查找 } // 启动插入开关功能 insertSwitchBeforeButton();
  • 思源笔记

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

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

    25534 引用 • 105619 回帖 • 1 关注
  • JavaScript

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

    733 引用 • 1280 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • AWS
    11 引用 • 28 回帖 • 6 关注
  • Office

    Office 现已更名为 Microsoft 365. Microsoft 365 将高级 Office 应用(如 Word、Excel 和 PowerPoint)与 1 TB 的 OneDrive 云存储空间、高级安全性等结合在一起,可帮助你在任何设备上完成操作。

    5 引用 • 34 回帖
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    246 引用 • 1338 回帖
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    78 引用 • 396 回帖
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 688 关注
  • 学习

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

    175 引用 • 540 回帖
  • 宕机

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

    13 引用 • 82 回帖 • 77 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • 微信

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

    133 引用 • 796 回帖
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 2 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 4 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    589 引用 • 3538 回帖
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 277 关注
  • Sillot

    Insights(注意当前设置 master 为默认分支)

    汐洛彖夲肜矩阵(Sillot T☳Converbenk Matrix),致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点。其中汐洛绞架(Sillot-Gibbet)基于自思源笔记(siyuan-note),前身是思源笔记汐洛版(更早是思源笔记汐洛分支),是智慧新录乄终端(多端融合,移动端优先)。

    主仓库地址:Hi-Windom/Sillot

    文档地址:sillot.db.sc.cn

    注意事项:

    1. ⚠️ 汐洛仍在早期开发阶段,尚不稳定
    2. ⚠️ 汐洛并非面向普通用户设计,使用前请了解风险
    3. ⚠️ 汐洛绞架基于思源笔记,开发者尽最大努力与思源笔记保持兼容,但无法实现 100% 兼容
    29 引用 • 25 回帖 • 116 关注
  • 反馈

    Communication channel for makers and users.

    121 引用 • 907 回帖 • 273 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    108 引用 • 295 回帖
  • Kotlin

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

    19 引用 • 33 回帖 • 74 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 529 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 504 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 1 关注
  • JSON

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

    52 引用 • 190 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖 • 2 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖 • 3 关注
  • 小说

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

    32 引用 • 108 回帖