DOM 工具库:Shadow DOM 穿透、异步元素查找、事件委托、样式注入
Цей скрипт не слід встановлювати безпосередньо. Це - бібліотека для інших скриптів для включення в мета директиву // @require https://update.greasyfork.org/scripts/559176/1715549/domToolkit.js
供油猴脚本通过 @require 引入的通用工具集。
| 工具 | 描述 |
|---|---|
| backgroundKeepAlive.user.js | 后台保活工具集 |
| domToolkit.user.js | DOM 操作工具库 |
专为 Tampermonkey 脚本设计的高性能 DOM 工具库,解决以下痛点:
// ==UserScript==
// @require https://update.greasyfork.org/scripts/XXXXX/xxx/domToolkit.js
// ==/UserScript==
支持 Shadow DOM 穿透的同步元素查找。
// 查找单个元素
const btn = DOMToolkit.query("button.submit");
// 查找所有匹配元素
const items = DOMToolkit.query(".item", {all: true});
// 在 Shadow DOM 中查找(默认启用)
const input = DOMToolkit.query("input.main", {shadow: true});
// 多选择器支持(返回第一个匹配)
const el = DOMToolkit.query(["button.submit", 'input[type="submit"]']);
// 使用自定义过滤函数
const textarea = DOMToolkit.query("[contenteditable]", {
shadow: true,
filter: (el) => el.offsetParent !== null && !el.closest("#my-panel"),
});
参数:
| 选项 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| parent | Node | document | 查询起点 |
| all | boolean | false | 是否返回所有匹配 |
| shadow | boolean | true | 是否穿透 Shadow DOM |
| maxDepth | number | 15 | 最大递归深度 |
| useCache | boolean | true | 是否使用缓存(有 filter 时自动禁用) |
| filter | function | null | 自定义过滤函数 (el) => boolean |
等待元素出现,支持超时控制。
// 等待元素出现(默认 5 秒超时)
const modal = await DOMToolkit.get(".modal");
// 自定义超时时间
const btn = await DOMToolkit.get("button.action", {timeout: 10000});
// 无限等待
const el = await DOMToolkit.get(".dynamic", {timeout: 0});
处理现在和未来所有匹配的元素。
// 处理所有(现有和未来的)按钮
const stop = DOMToolkit.each("button.action", (btn, isNew) => {
btn.style.color = "blue";
if (isNew) console.log("New button added");
});
// 稍后停止监听
stop();
// 返回 false 可提前停止
DOMToolkit.each(".item", (el) => {
if (el.id === "target") {
console.log("Found target");
return false; // 停止监听
}
});
事件委托,自动处理 Shadow DOM 中的事件。
// 委托点击事件
const remove = DOMToolkit.on("click", ".item", (event, target) => {
console.log("Item clicked:", target);
});
// 稍后移除
remove();
// 捕获阶段
DOMToolkit.on("click", ".btn", callback, {capture: true});
// 创建元素
const btn = DOMToolkit.create(
"button",
{
className: "primary",
id: "submit",
style: {color: "white", background: "blue"},
onClick: () => console.log("clicked"),
},
"Submit"
);
// 从 HTML 字符串创建
const div = DOMToolkit.createFromHTML('<div class="card"><p>Hello</p></div>');
// 获取 ID 映射
const {root, title, content} = DOMToolkit.createFromHTML(
`
<div id="container">
<h1 id="title">Title</h1>
<p id="content">Content</p>
</div>
`,
{mapIds: true}
);
// 全局样式
DOMToolkit.css(".highlight { background: yellow; }", "my-styles");
// 向单个 Shadow DOM 注入
DOMToolkit.cssToShadow(shadowRoot, css, "shadow-styles");
// 向所有 Shadow DOM 注入
DOMToolkit.cssToAllShadows(css, "all-shadow-styles");
// 过滤特定 Shadow Host
DOMToolkit.cssToAllShadows(css, "id", {
filter: (host) => !host.closest(".sidebar"),
});
DOMToolkit.walkShadowRoots((shadowRoot, host) => {
console.log("Found shadow root on:", host.tagName);
});
// 使用默认逻辑(Shadow DOM 优先,然后 documentElement/body)
const scroller = DOMToolkit.findScrollContainer();
// 提供站点特定的选择器(优先匹配)
const scroller = DOMToolkit.findScrollContainer({
selectors: [".chat-mode-scroller", ".conversation-container", "main"],
});
DOMToolkit.clear(element); // 清空元素内容
DOMToolkit.clearCache(); // 清除缓存
DOMToolkit.configCache({enabled: false}); // 禁用缓存
DOMToolkit.destroy(); // 销毁实例
解决浏览器后台标签页节流问题的通用工具集,包含三大模块。
// ==UserScript==
// @require https://update.greasyfork.org/scripts/559089/1714656/background-keep-alive.js
// ==/UserScript==
基于 Web Worker 的保活定时器,绑定后台环境下不被节流。
const timer = new BackgroundTimer(() => {
console.log("心跳:", new Date().toTimeString());
}, 1000);
timer.start(); // 启动
timer.stop(); // 停止
timer.setInterval(2000); // 动态调整间隔
timer.isRunning(); // 获取状态
timer.destroy(); // 销毁实例
使用静音音频对抗 Chrome 5 分钟强力休眠。
⚠️ 需要用户交互后才能启动(浏览器自动播放策略限制)
const audio = new AudioKeepAlive();
// 需要在用户交互后启动
document.addEventListener("click", () => audio.start(), {once: true});
audio.stop(); // 停止
audio.isActive(); // 获取状态
audio.destroy(); // 销毁实例
Hook Fetch 和 XHR 监控任务完成状态,使用防抖 + 活跃计数器算法。
const monitor = new NetworkMonitor({
// 监控的 URL 模式(包含匹配)
// 注意:避免使用通用 RPC 方法如 batchexecute,会产生误判
urlPatterns: ["BardFrontendService", "StreamGenerate"],
// 静默判定时间(毫秒)
silenceThreshold: 3000,
// 任务完成回调
onComplete: (ctx) => {
console.log("任务完成", ctx);
// ctx = { activeCount, lastUrl, timestamp }
},
// 任务开始回调(可选)
onStart: (ctx) => {
console.log("任务开始", ctx);
},
// DOM 二次验证(可选,自定义)
domValidation: (ctx) => {
// 返回 true 表示验证通过,触发 onComplete
// 返回 false 表示还需等待
return !document.querySelector(".stop-button");
},
});
monitor.start(); // 开始监控
monitor.stop(); // 停止监控
monitor.isIdle(); // 是否空闲
monitor.getActiveCount(); // 活跃请求数
monitor.destroy(); // 销毁实例
算法说明: