[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();
  • 思源笔记

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

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

    26034 引用 • 108049 回帖
  • JavaScript

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

    730 引用 • 1282 回帖 • 5 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 59 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    947 引用 • 1460 回帖 • 2 关注
  • C

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

    86 引用 • 165 回帖
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    497 引用 • 934 回帖
  • Unity

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

    25 引用 • 7 回帖 • 121 关注
  • Office

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

    5 引用 • 34 回帖
  • OneNote
    1 引用 • 3 回帖 • 1 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖 • 1 关注
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    20 引用 • 245 回帖 • 232 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 1 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 119 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 464 关注
  • 安全

    安全永远都不是一个小问题。

    199 引用 • 818 回帖
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 5 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    93 引用 • 122 回帖 • 619 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 3 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 37 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 404 关注
  • Sillot

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

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

    主仓库地址:Hi-Windom/Sillot

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

    注意事项:

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

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    171 引用 • 1537 回帖 • 2 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    954 引用 • 944 回帖 • 1 关注
  • Flume

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

    9 引用 • 6 回帖 • 661 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    187 引用 • 826 回帖