elmGetter 水果玉米 魔改版 文档
本帖最后由 溯水流光 于 2025-5-28 18:42 编辑# elmGetter 水果玉米 魔改版 文档
> 原版的地址: https://bbs.tampermonkey.net.cn/thread-2726-1-1.html
>
> 感谢 cxxjackie 大佬的开源, cxxjackie 大佬的代码未明确开源协议,我实在是太欣赏这段代码,没忍住先 fork 了,在此诚挚地向 cxxjackie 大佬道个歉。如果涉及任何侵权问题,我一定第一时间下架,绝不含糊。
>
> 如果我魔改后的库能合并到主分支,将会是最棒的。
### 修改源码的契机
elmGetter原有的部分代码设计用起来不太顺手,所以我决定对它进行魔改,添加自己需要的功能。
我希望给 elmGetter 添加三个功能:一是增加超时错误处理回调参数,在未找到元素时打印日志,便于调试;二是通过 bool 参数控制超时时,让 promise 保持 pending 或者 resolve (null);三是支持自定义超时时 resolve 的值,比如 resolve 一个无法删除的 div。
我不仅把这些参数保留为函数参数,还将其设为 elmGetter 成员变量,便于统一设置。为传参方便,我重构了几乎所有函数的传参方式,支持对象传参,无需记参数顺序。
> require:
>
> // @require https://scriptcat.org/lib/2847/3.0.1/ElementGetter%20%E6%B0%B4%E6%9E%9C%E7%8E%89%E7%B1%B3%20%E9%AD%94%E6%94%B9%E7%89%88.js
## 魔改版 vs 原版
和原版相比,elmGetter水果玉米魔改版主要在优化开发体验上做了提升和改善。
+ ✅ 新增超时回调,方便日志输出,便于调试代码;
+ ✅ 新增统一设置超时时间功能,方便在脚本发布时去掉超时时间;
+ ✅ 还新增了超时后的行为控制,能通过参数或成员变量设置超时回调、超时后promise的状态,以及超时后resolve降级元素。
+ ✅ 我会持续维护这个库,一旦原版有更新,将及时进行合并。
+ ✅ 接口参数进行了重构,使用option方式传参,增加代码的可读性,和方便了接口调用
+ ❎ 由于进行了接口重构,这个库将不兼容原版库
### 简单的代码示例
原版的代码:
```js
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-02-21
// @descriptiontry to take over the world!
// @author You
// @match http://127.0.0.1:5500/playground.html
// @icon https://www.google.com/s2/favicons?sz=64&domain=0.1
// @grant unsafeWindow
// @require https://scriptcat.org/lib/513/2.0.1/ElementGetter.js#sha256=V0EUYIfbOrr63nT8+W7BP1xEmWcumTLWu2PXFJHh5dg=
// ==/UserScript==
(async function () {
'use strict';
// TODO: 发布脚本时, 请去掉延时, 延时会导致 elmGetter 启动 setTimeout, 降低脚本性能, 这里设置延时, 仅仅是方便日志打印和调试bug
const timeout = 300;
const childSelector = ".child";
let el1 = await elmGetter.get(childSelector, timeout);
if (el1 === null) {
console.warn(` ${childSelector} 没有找到`);
}
const errorSelector = ".error";
// TODO: 发布脚本时, 请去掉延时, 延时会导致 elmGetter 启动 setTimeout, 降低脚本性能, 这里设置延时, 仅仅是方便日志打印和调试bug
let el2 = await elmGetter.get(errorSelector, timeout);
if (el2 === null) {
console.warn(` ${errorSelector} 没有找到`);
}
})();
```
魔改版:
```js
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-02-21
// @descriptiontry to take over the world!
// @author You
// @match http://127.0.0.1:5500/playground.html
// @icon https://www.google.com/s2/favicons?sz=64&domain=0.1
// @grant unsafeWindow
// @require [库地址]
// ==/UserScript==
// 没有中间层
initGlobalVar();
(async function () {
'use strict';
// TODO: 发布脚本时, 请去掉延时, 延时会导致 elmGetter 启动 setTimeout, 降低脚本性能, 这里设置延时, 仅仅是方便日志打印和调试bug
elmGetter.timeout = 300;
let el1 = await elmGetter.get(".comments");
let el2 = await elmGetter.get(".error");
})();
```
## 接口文档
> 使用说明: 基本上和原版一致, 看cxxjackie的原文就好了, https://bbs.tampermonkey.net.cn/thread-2726-1-1.html, 这里主要的是接口参数有变化, 变成了options 传参
### get
```js
/**
* 异步的 querySelector
* @param selector
* @param options 一个对象
*- parent 父元素, 默认值是 document
*- timeout 设置 get 的超时时间, 默认值是 elmGetter.timeout, 其值默认为 0
* - 如果该值为 0, 表示永不超时, 如果 selector 有误, 返回的 Promise 将永远 pending
* - 如果该值不为 0, 表示等待多少毫秒, 和 setTimeout 单位一致
*- onError 超时后的失败回调, 参数为 selector, 默认值为 elmGetter.onError, 其默认行为是 console.warn 打印 selector
*- isPending 超时后 Promise 是否仍然保持 pending, 默认值为 elmGetter.isPending, 其值默认为 true
*- errEl 超时后 Promise 返回的值, 需要 isPending 为 false 才能有效, 默认值为 elmGetter.errorEl, 其值默认为一个 class 为一个 class 为 no-found 的元素
* @returns {Promise<Awaited<unknown>[]>|Promise<unknown>}
*/
get(selector, options = {}) {
let {
parent = doc,
timeout = this.timeout,
onError = this.onError,
isPending = this.isPending,
errEl = this.errEl,
} = options;
```
### each
```js
/**
* 为父节点设置监听,所有符合选择器的元素(包括页面已有的和新插入的)都将被传给回调函数处理,
* each方法适用于各种滚动加载的列表(如评论区),或者发生非刷新跳转的页面等
* @param selector
* @param callback 回调函数, 只在每个元素上触发一次。 回调函数接收2个参数,第一个是符合选择器的元素,第二个表明该元素是否为新插入的(已有为false,插入为true)
* @param options 一个对象
*- parent 父元素, 默认值是 document
*/
each(selector, callback, options = {}) {
let {
parent = doc,
} = options;
```
### create
```js
/**
* 将html字符串解析为元素
* @param domString
* @param options 一个对象
*- returnList 布尔值,是否返回以 id 作为索引的元素列表, 默认值为 false
*- parent 父节点,将创建的元素添加到父节点末尾处, 如果不指定, 解析后的元素将
* @returns {Element|{}|null} 元素或对象,取决于returnList参数
*/
create(domString, options = {}) {
let {
returnList = false,
parent = null
} = options;
```
### 成员变量
```js
let errEl = document.createElement('div');
errEl.classList.add('no-found');
errEl.remove = () => {};
return {
timeout: 0,
onError:(selector) => {console.warn(` selector为: ${selector} 的查询超时`)},
isPending: true,
errEl,
```
## 配套的完整指南
我为elmGetter打造了一整套原版源码分析指南,旨在帮大家掌握源码修改技巧,让elmGetter成为你的如意兵器。
指南内容涵盖MutationObserve快速上手、源码分析思路与知识点补充,还将经典的WaitForKeyElememt异步库设计作为附录。
目前已近万字,我仍在精简润色,后续会拆分成多篇文章,整理目录后发布于脚本猫论坛,敬请期待!
(◦˙▽˙◦)
文档链接: https://bbs.tampermonkey.net.cn/thread-8196-1-1.html
## 未整理过的碎碎念
### 原版 vs 魔改版
原版存在的问题: 当一个脚本有40,50个异步查询的时候,开发的过程中不小心填错了某个选择器,或某个选择器失效了,由于elmGetter的默认策略就是无限等待pending,也不会控制台输出,所以排查问题变得比较棘手
唯一的解决方案是设置timeout参数,elmGetter超时后,判断其resolve的值是否为null
这里存在三个问题,
+ 第一是要写大量的 if 判断
+ 二是我就想超时后pending,原版是无法做到的
+ 第三,elmGetter使用timeout参数是极其耗费性能的操作,因为底层会起很多的setTimeout,等到生产环境后,还得一个个去掉timeout, 得统一方便地设置延时
使用了魔改库后,解决了这三个问题
### 摘要
摘要: elmGetter 魔改版的主要改进,增加了错误处理回调,方便找不到元素的时候打印日志,排查错误
在elmGetter 魔改版找不到元素的时候,默认错误处理是console.warn
而且支持全局统一设置超时时间,等发布脚本的时候直接把那行注释掉就可以了
### 明细
+ ✅ 添加了 elmGetter.timeout 成员变量, 方便设置全局 timeout, 来排查代码错误,
等实际脚本发布的时候, 把设置 timeout 代码去掉就可以了, 避免elmGetter 创建过多的 setTimeout 来浪费脚本性能
+ ✅ 添加了elmGetter.get错误处理参数, 在超时后, 调用你的失败回调, 方便超时进行日志输出, 定位脚本bug
+ ✅ elmGetter.onError 支持设置全局错误处理, 来统一继续超时后的错误处理, 默认的全局错误处理是() => console.warn(": 找不到")
+ ✅ elmGetter.get 找不到目标后有两种处理:
1. 如果没有设置timeout, 会一直pedding, 这个可以用于发布环境, 但如果在开发环境使用, 因为没有日志打印, 容易找不到bug
2. 如果设置了timeout, 原版会resolve(null), 我们这里支持通过isPedding参数和elmGetter.isPedding设置超时后, 调用完失败回调后, 仍然pedding, 也支持设置errorEl和elmGetter.errorEl来设置resolve(errorEl)
❎代码参数部分进行了全面重构, 不向后兼容以前版本的elmGetter
## 后记
感谢 cxxjackie 大佬的开源,正是有了他的贡献,我才能站在巨人的肩膀上;感谢脚本猫脚本站的站长和管理员,正是有了这个平台,脚本分享和交流才变得如此便捷。最后,衷心感谢每一位用户的支持!祝你们用得开心!
✿✿ヽ(°▽°)ノ✿完结撒花!
感谢哥哥的分享,社区因为有你更美好 c大的代码是真的优美
我刚开始写指南的时候
也特别喜欢去拆他代码看思路 哥哥太厉害了 ggnb!!! 首先感谢支持!开源协议的问题我最初担心的是GF那边分发后被添加广告代码,目前来看至少在库这块没有这种趋势,且GF已寄~ 对于正常的分发修改行为我本身并无反对,后续将添加LGPL协议。
我确实没有考虑太多开发环境下的体验问题,感谢你对超时控制这一块的建议。option传参由于不向下兼容,我认为暂时没有必要做这种层级的改动(当然你可以在你的分发版本下沿用这一改动),我的想法是只添加统一的超时控制,这样既照顾开发体验,也不与原接口冲突。
你所提出的几个参数可以合并至一处,统一使用超时回调来处理,并以该回调函数的返回值来决定超时后Promise的行为:返回任何非undefined值都将使get方法输出该值,否则维持pending状态。是否输出控制台警告、超时元素等交由开发者决定,库不必包含这部分代码,调用示例如下:
```js
elmGetter.onTimeout(selector => {
console.warn(` ${selector}`);
return elmGetter.create('<div class="no-found"></div>');
});
```
关于此库的后续更新:create方法是否有废弃的必要?我当初只是随手加进来的,如今看来已有点格格不入了,我不太明确它继续存在的必要性,所以在这里顺便问问你们的意见。 cxxjackie 发表于 2025-2-27 22:14
首先感谢支持!开源协议的问题我最初担心的是GF那边分发后被添加广告代码,目前来看至少在库这块没有这 ...
感谢大佬的授权和肯定!我认为 create 方法保留挺好的,它在动态生成元素场景下仍有实用价值,并未显得冗余。 hysaoh 发表于 2025-2-24 17:29
哥哥太厉害了
谢谢哥哥的肯定和支持!! empyrealtear 发表于 2025-2-24 17:46
ggnb!!!
谢谢你的支持!! ヾ(≧▽≦*)o 学习了!
页:
[1]
2