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

异步获取元素的脚本库 ElementGetter (更新至1.2.0)

[复制链接]
  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    13

    主题

    416

    帖子

    723

    积分

    荣誉开发者

    Rank: 10Rank: 10Rank: 10

    积分
    723

    活跃会员热心会员突出贡献三好学生猫咪币纪念章中秋纪念章国庆纪念章荣誉开发者

    发表于 2022-7-10 11:47:04 | 显示全部楼层 | 阅读模式

    本帖最后由 cxxjackie 于 2022-8-13 12:05 编辑

    本帖最后由 cxxjackie 于 2022-8-2 12:09 编辑

    这是一个供其他脚本使用的外部库,不应被直接安装,请使用以下地址在你的脚本中引用:

    // @require https://scriptcat.org/lib/513/1.2.0/ElementGetter.js

    这是一个异步获取元素的脚本库。不少人写脚本都碰到过元素延迟加载的问题,使用定时器获取不仅实时性不足,还有性能问题,DOMNodeInserted的性能也不好,一般都推荐MutationObserver的方案。但是MutationObserver的语法较复杂,回调函数的写法也不易于使用,因此本库将相关代码加以封装,让元素获取一步到位,方便脚本的快速开发。

    初始化

    const elmGetter = new ElementGetter(jQuery);

    jQuery 可选,jQuery引用,即$。
    若传入jQuery,get方法和each方法的选择器改为jQuery选择器,返回jQuery节点。注意:jQuery必须为页面原有或脚本引入,库本身不包含jQuery。
    尽管ElementGetter兼容低版本jQuery,但不同版本的jQuery对选择器的支持不尽相同,请自行测试或查询相关文档,以免得不到预期结果。
    elmGetter具有get、each和create三个方法。1.2.0版本后,remove方法已废弃。

    方法

    get(selector[, parent][, timeout])

    selector 必须, 选择器或选择器数组。
    parent 可选,父节点,默认值document。
    timeout 可选,超时时间(毫秒),默认值0。
    返回值 Promise,selector为选择器时返回元素,为数组时返回元素数组。

    根据选择器或选择器数组获取元素,选择器同querySelector。若元素已存在则返回,否则监听父节点的元素插入,直至获取到元素或达到超时时间为止。返回类型为Promise,使用.then或async/await取得元素:

    // 回调写法
    (function() {
        elmGetter.get('div').then(div => {
            console.log(div);
        });
    })();
    // 同步写法
    (async function() {
        const div = await elmGetter.get('div');
        console.log(div);
    })();

    使用async/await时,若需要在同一父节点上同时获取多个元素,多次await可能造成性能问题,可以用Promise.all优化性能,库内部会尝试将多个监听器合并为一个。为简化这一流程,get方法的第一个参数允许是选择器数组,效果等同于Promise.all,参考以下示例:

    // 以下两种写法等价
    const [elm1, elm2, elm3] = await Promise.all([
      elmGetter.get('.elm1'),
      elmGetter.get('.elm2'),
      elmGetter.get('.elm3')
    ]);
    const [elm1, elm2, elm3] = await elmGetter.get(['.elm1', '.elm2', '.elm3']);

    each(selector[, parent], callback)

    selector 必须,选择器。
    parent 可选,父节点,默认值document。
    callback 必须,回调函数。
    返回值 无。

    为父节点设置监听,所有符合选择器的元素(包括页面已有的和新插入的)都将被传给回调函数处理。1.1.0版本后,回调函数只在每个元素上触发一次。 回调函数接收2个参数,第一个是符合选择器的元素,第二个表明该元素是否为新插入的(已有为false,插入为true)。each方法适用于各种滚动加载的列表(如评论区),或者发生非刷新跳转的页面等,参考以下示例:

    // b站评论区自动展开回复
    elmGetter.each('.reply-item', document, reply => {
        const btn = reply.querySelector('.view-more-btn');
        if (btn) btn.click();
    });

    令回调函数返回false即可移除监听,参考以下示例:

    const listener = elmGetter.each('div', document, (elm, isInserted) => {
        if (isInserted) {
            return false;
        }
    });

    create(domString, parent)

    domString 必须,待解析的字符串。
    parent 可选,父节点,将创建的元素添加到父节点末尾处。
    返回值 解析后的第一个元素。

    将html字符串解析为元素。注意,该方法只会返回一个元素,多个元素并列时返回第一个。示例:

    const div = elmGetter.create('<div class="mydiv">Hello world</div>');

    综合示例

    以下综合示例展示了该库是如何工作的:

    // ==UserScript==
    // @name         油猴中文网一键登录 - 示例脚本
    // @namespace    ...
    // @author       ...
    // @version      1.0
    // @match        https://bbs.tampermonkey.net.cn/*
    // @require      https://scriptcat.org/lib/513/1.2.0/ElementGetter.js
    // ==/UserScript==
    
    (function() {
        'use strict';
        const $ = new ElementGetter();
        $.each('[id^="loginform_"]', document, form => {
            const submit = form.querySelector('[name="loginsubmit"]');
            const button = $.create(`
    <button class="pn pnc" type="submit" tabindex="1" style="margin-left: 20px;">
        <strong>一键登录</strong>
    </button>
            `, submit.parentNode);
            button.addEventListener('click', async e => {
                e.stopImmediatePropagation();
                // 这里也可以直接用querySelector,代码仅作为示例
                const [username, password, cookietime] = await $.get([
                    '[id^="username_"]',
                    '[id^="password3_"]',
                    '[id^="cookietime_"]'
                ], form);
                username.value = '12345'; // 用户名
                password.value = '54321'; // 密码
                cookietime.checked = true;
                submit.click();
            }, true);
        });
    })();

    更新日志

    1.0.0
    初始版本

    1.1.0
    1.修复each方法的回调函数可能在相同元素上反复触发的问题,现在每个元素只会触发一次。
    2.新增jQuery支持。
    3.get方法和each方法允许单独省略parent参数。

    1.1.1
    1.修复上个版本的一点遗留问题(有句代码忘了删- -)。
    2.each的回调函数现在可以通过return false移除监听(考虑改动remove机制,可能不向下兼容)。

    1.2.0
    1.废弃remove方法,改用return false的方式移除监听,each方法不再具有返回值。
    2.废弃MutationEvent兼容。get方法和each方法现在额外监听属性变化,以使属性选择器的结果更准确。
    3.each方法优化。
    4.create方法新增parent参数。
    5.精简了下代码,代码量减少约20%。

  • TA的每日心情
    开心
    昨天 09:04
  • 签到天数: 167 天

    [LV.7]常住居民III

    25

    主题

    647

    帖子

    6280

    积分

    荣誉开发者

    精通各种语言的HelloWord!

    Rank: 10Rank: 10Rank: 10

    积分
    6280

    猫咪币纪念章活跃会员三好学生热心会员中秋纪念章国庆纪念章荣誉开发者家财万贯

    发表于 2022-7-10 13:04:52 | 显示全部楼层
    正在用,感谢cxxjackie大佬
    回复

    使用道具 举报

  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 57 天

    [LV.5]常住居民I

    354

    主题

    3128

    帖子

    3129

    积分

    管理员

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

    Rank: 10Rank: 10Rank: 10

    积分
    3129

    猫咪币纪念章国庆纪念章中秋纪念章荣誉开发者家财万贯管理员

    发表于 2022-7-10 13:35:51 | 显示全部楼层
    之前一直想封
    结果拖来拖去一直没搞...
    终于cxxjackie大佬按捺不住了!
    哈哈哈哈
    其实还想看cxxjackie大佬写分析文章!
    简单易懂还涨知识
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 57 天

    [LV.5]常住居民I

    354

    主题

    3128

    帖子

    3129

    积分

    管理员

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

    Rank: 10Rank: 10Rank: 10

    积分
    3129

    猫咪币纪念章国庆纪念章中秋纪念章荣誉开发者家财万贯管理员

    发表于 2022-7-10 13:36:14 | 显示全部楼层
    也加入开发指南可以吗
    哥哥
    还有一个很呆的问题就是
    为啥要加#

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

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

    [LV.1]初来乍到

    13

    主题

    416

    帖子

    723

    积分

    荣誉开发者

    Rank: 10Rank: 10Rank: 10

    积分
    723

    活跃会员热心会员突出贡献三好学生猫咪币纪念章中秋纪念章国庆纪念章荣誉开发者

    发表于 2022-7-10 13:45:42 | 显示全部楼层
    李恒道 发表于 2022-7-10 13:36
    也加入开发指南可以吗
    哥哥

    可以吧,不过我感觉这个没什么技术性的分析,只是个工具。
    回复

    使用道具 举报

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

    [LV.1]初来乍到

    13

    主题

    416

    帖子

    723

    积分

    荣誉开发者

    Rank: 10Rank: 10Rank: 10

    积分
    723

    活跃会员热心会员突出贡献三好学生猫咪币纪念章中秋纪念章国庆纪念章荣誉开发者

    发表于 2022-7-10 13:51:34 | 显示全部楼层
    李恒道 发表于 2022-7-10 13:36
    也加入开发指南可以吗
    哥哥
    还有一个很呆的问题就是

    #号是类的私有属性,一个比较新的特性(我也是尝试着用的哈哈)。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 57 天

    [LV.5]常住居民I

    354

    主题

    3128

    帖子

    3129

    积分

    管理员

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

    Rank: 10Rank: 10Rank: 10

    积分
    3129

    猫咪币纪念章国庆纪念章中秋纪念章荣誉开发者家财万贯管理员

    发表于 2022-7-11 11:23:16 | 显示全部楼层
    cxxjackie 发表于 2022-7-10 13:51
    #号是类的私有属性,一个比较新的特性(我也是尝试着用的哈哈)。

    c大!
    碰到问题了
    比如https://unpkg.com/element-ui/lib/theme-chalk/index.css
    如果直接resource然后gm_addstyle会导致错乱
    比如用link标签引入...
    这种油猴有啥好的方案吗
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

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

    [LV.1]初来乍到

    13

    主题

    416

    帖子

    723

    积分

    荣誉开发者

    Rank: 10Rank: 10Rank: 10

    积分
    723

    活跃会员热心会员突出贡献三好学生猫咪币纪念章中秋纪念章国庆纪念章荣誉开发者

    发表于 2022-7-11 12:20:27 | 显示全部楼层
    李恒道 发表于 2022-7-11 11:23
    c大!
    碰到问题了
    比如https://unpkg.com/element-ui/lib/theme-chalk/index.css

    相对路径的问题,当成字符串处理一下就好了:
    1. let css = GM_getResourceText('css');
    2. css = css.replace(/(?<=url\()(?=fonts)/g, 'https://unpkg.com/element-ui@2.15.9/lib/theme-chalk/');
    3. GM_addStyle(css);
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 57 天

    [LV.5]常住居民I

    354

    主题

    3128

    帖子

    3129

    积分

    管理员

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

    Rank: 10Rank: 10Rank: 10

    积分
    3129

    猫咪币纪念章国庆纪念章中秋纪念章荣誉开发者家财万贯管理员

    发表于 2022-7-11 14:51:47 | 显示全部楼层
    cxxjackie 发表于 2022-7-11 12:20
    相对路径的问题,当成字符串处理一下就好了:

    这就...
    很尴尬了
    我以为是编码问题研究半天编码
    结果是路径问题
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

    该用户从未签到

    30

    主题

    207

    帖子

    207

    积分

    荣誉开发者

    Rank: 10Rank: 10Rank: 10

    积分
    207

    荣誉开发者

    发表于 2022-7-11 18:34:45 | 显示全部楼层
    为什么哥哥对原生的api这么熟悉
    回复

    使用道具 举报

    发表回复

    本版积分规则

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