上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

elmGetter 水果玉米 魔改版 文档

[复制链接]
  • TA的每日心情
    奋斗
    2025-3-1 19:55
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    10

    主题

    11

    回帖

    124

    积分

    荣誉开发者

    积分
    124

    油中2周年新人报道荣誉开发者

    发表于 2025-2-24 15:23:57 | 显示全部楼层 | 阅读模式

    如何使用? 库问题反馈 给库评分 查看代码

    本帖最后由 溯水流光 于 2025-2-25 22:22 编辑

    本帖最后由 溯水流光 于 2025-2-24 15:27 编辑

    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.0/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方式传参,增加代码的可读性,和方便了接口调用

    • ❎ 由于进行了接口重构,这个库将不兼容原版库

    简单的代码示例

    原版的代码:

    // ==UserScript==
    // @name         New Userscript
    // @namespace    http://tampermonkey.net/
    // @version      2025-02-21
    // @description  try 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(`[elmGetter] [get失败] ${childSelector} 没有找到`);
        }
    
        const errorSelector = ".error";
        // TODO: 发布脚本时, 请去掉延时, 延时会导致 elmGetter 启动 setTimeout, 降低脚本性能, 这里设置延时, 仅仅是方便日志打印和调试bug
        let el2 = await elmGetter.get(errorSelector, timeout);
        if (el2 === null) {
            console.warn(`[elmGetter] [get失败] ${errorSelector} 没有找到`);
        }
    })();

    魔改版:

    // ==UserScript==
    // @name         New Userscript
    // @namespace    http://tampermonkey.net/
    // @version      2025-02-21
    // @description  try 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

    /**
     * 异步的 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

    /**
     * 为父节点设置监听,所有符合选择器的元素(包括页面已有的和新插入的)都将被传给回调函数处理,
     * each方法适用于各种滚动加载的列表(如评论区),或者发生非刷新跳转的页面等
     * @param selector
     * @param callback 回调函数, 只在每个元素上触发一次。 回调函数接收2个参数,第一个是符合选择器的元素,第二个表明该元素是否为新插入的(已有为false,插入为true)
     * @param options 一个对象
     *  - parent 父元素, 默认值是 document
     */
    each(selector, callback, options = {}) {
        let {
            parent = doc,
        } = options;

    create

    /**
     * 将html字符串解析为元素
     * @param domString
     * @param options 一个对象
     *  - returnList 布尔值,是否返回以 id 作为索引的元素列表, 默认值为 false
     *  - parent 父节点,将创建的元素添加到父节点末尾处, 如果不指定, 解析后的元素将
     * @returns {Element|{}|null} 元素或对象,取决于returnList参数
     */
    create(domString, options = {}) {
        let {
            returnList = false,
            parent = null
        } = options;

    成员变量

    let errEl = document.createElement('div');
    errEl.classList.add('no-found');
    errEl.remove = () => {};
    
    return {
        timeout: 0,
        onError:  (selector) => {console.warn(`[elmGetter] [get失败] 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]: 找不到")
    • ✅ elmGetter.get 找不到目标后有两种处理:
      1. 如果没有设置timeout, 会一直pedding, 这个可以用于发布环境, 但如果在开发环境使用, 因为没有日志打印, 容易找不到bug
      2. 如果设置了timeout, 原版会resolve(null), 我们这里支持通过isPedding参数和elmGetter.isPedding设置超时后, 调用完失败回调后, 仍然pedding, 也支持设置errorEl和elmGetter.errorEl来设置resolve(errorEl)
        ❎代码参数部分进行了全面重构, 不向后兼容以前版本的elmGetter

    后记

    感谢 cxxjackie 大佬的开源,正是有了他的贡献,我才能站在巨人的肩膀上;感谢脚本猫脚本站的站长和管理员,正是有了这个平台,脚本分享和交流才变得如此便捷。最后,衷心感谢每一位用户的支持!祝你们用得开心!

    ✿✿ヽ(°▽°)ノ✿完结撒花!

    已有5人评分好评 油猫币 贡献 理由
    cocang + 1 + 1
    mashuai + 1 + 1 ggnb!
    empyrealtear + 1 + 3 ggnb!
    hysaoh + 1 + 5 + 1 ggnb!
    王一之 + 1 + 4 赞一个!

    查看全部评分 总评分:好评 +5  油猫币 +14  贡献 +1 

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    309

    主题

    4356

    回帖

    4207

    积分

    管理员

    积分
    4207

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2025-2-24 15:40:56 | 显示全部楼层
    感谢哥哥的分享,社区因为有你更美好
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2025-1-31 20:04
  • 签到天数: 195 天

    [LV.7]常住居民III

    745

    主题

    6519

    回帖

    7192

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    7192

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2025-2-24 16:48:44 | 显示全部楼层

    c大的代码是真的优美
    我刚开始写指南的时候
    也特别喜欢去拆他代码看思路

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.com/a/lihengdao666
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-2-28 14:15
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    38

    主题

    250

    回帖

    381

    积分

    版主

    积分
    381

    油中2周年生态建设者

    发表于 2025-2-24 17:29:19 | 显示全部楼层
    哥哥太厉害了
    一叶叶,一声声,空阶滴到明。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    前天 00:00
  • 签到天数: 26 天

    [LV.4]偶尔看看III

    2

    主题

    7

    回帖

    75

    积分

    初级工程师

    积分
    75
    发表于 2025-2-24 17:46:01 | 显示全部楼层
    ggnb!!!
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    892

    回帖

    1389

    积分

    荣誉开发者

    积分
    1389

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2025-2-27 22:14:03 | 显示全部楼层

    首先感谢支持!开源协议的问题我最初担心的是GF那边分发后被添加广告代码,目前来看至少在库这块没有这种趋势,且GF已寄~ 对于正常的分发修改行为我本身并无反对,后续将添加LGPL协议。
    我确实没有考虑太多开发环境下的体验问题,感谢你对超时控制这一块的建议。option传参由于不向下兼容,我认为暂时没有必要做这种层级的改动(当然你可以在你的分发版本下沿用这一改动),我的想法是只添加统一的超时控制,这样既照顾开发体验,也不与原接口冲突。
    你所提出的几个参数可以合并至一处,统一使用超时回调来处理,并以该回调函数的返回值来决定超时后Promise的行为:返回任何非undefined值都将使get方法输出该值,否则维持pending状态。是否输出控制台警告、超时元素等交由开发者决定,库不必包含这部分代码,调用示例如下:

    elmGetter.onTimeout(selector => {
        console.warn(`[elmGetter] [timeout] ${selector}`);
        return elmGetter.create('<div class="no-found"></div>');
    });

    关于此库的后续更新:create方法是否有废弃的必要?我当初只是随手加进来的,如今看来已有点格格不入了,我不太明确它继续存在的必要性,所以在这里顺便问问你们的意见。

    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2025-3-1 19:55
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    10

    主题

    11

    回帖

    124

    积分

    荣誉开发者

    积分
    124

    油中2周年新人报道荣誉开发者

    发表于 2025-2-28 11:29:17 | 显示全部楼层
    cxxjackie 发表于 2025-2-27 22:14
    [md]首先感谢支持!开源协议的问题我最初担心的是GF那边分发后被添加广告代码,目前来看至少在库这块没有这 ...

    感谢大佬的授权和肯定!我认为 create 方法保留挺好的,它在动态生成元素场景下仍有实用价值,并未显得冗余。
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2025-3-1 19:55
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    10

    主题

    11

    回帖

    124

    积分

    荣誉开发者

    积分
    124

    油中2周年新人报道荣誉开发者

    发表于 2025-3-1 19:54:11 | 显示全部楼层

    谢谢哥哥的肯定和支持!!
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2025-3-1 19:55
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    10

    主题

    11

    回帖

    124

    积分

    荣誉开发者

    积分
    124

    油中2周年新人报道荣誉开发者

    发表于 2025-3-1 19:54:59 | 显示全部楼层

    谢谢你的支持!! ヾ(≧▽≦*)o
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表