油猴脚本能拦截$(document).ready 吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tsccai
V2EX    jQuery

油猴脚本能拦截$(document).ready 吗?

  •  
  •   Tsccai 2023-09-13 16:30:14 +08:00 3714 次点击
    这是一个创建于 757 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在研究一个古老的系统,想写一个油猴脚本。我发现页面中有这样的代码:

    $(document).ready( closeIt(); ) 

    程序会在 dom 加载完后检查浏览器版本,不满足直接关闭页面窗口。 那么,油猴脚本能否拦截 ready 函数,不让其执行原来的程序呢?

    22 条回复    2024-04-09 13:50:54 +08:00
    kkk9
        1
    kkk9  
       2023-09-13 18:25:08 +08:00
    实践出真知!

    ```Javascript
    (function() {
    'use strict';
    $(document).ready(function() {
    // ... 你自己的代码
    }
    })
    ```
    kkk9
        2
    kkk9  
       2023-09-13 18:25:50 +08:00
    漏了一个) 记得自己补足
    ysc3839
        3
    ysc3839  
       2023-09-13 18:31:52 +08:00 via Android
    拦截 ready 肯定行呀,替换掉“$”,然后调用原函数,判断一下传入的参数是不是 document ,或者返回的对象有没有 ready 函数,有的话替换掉 ready 。
    不过个人感觉从检查浏览器版本那下手会更好吧?建议能给原网页。
    caomu
        4
    caomu  
       2023-09-13 19:11:32 +08:00 via Android
    如果不是直接载入脚本,而是用浏览器扩展载入的话,主流的 gm 、tm 、vm 扩展应该都是支持设置脚本生效时间,默认是页面载入完成后,也可以手工改成载入开始时。
    vvhy
        5
    vvhy  
       2023-09-13 19:33:56 +08:00
    用//@run-at document-start ,还不够快的话去设置开启即时注入
    Tsccai
        6
    Tsccai  
    OP
       2023-09-13 23:39:40 +08:00
    @ysc3839 呃,因为网页其他代码还需要用 jQuery ,所以直接干掉$是不可取的。我是准备在原本的 closeIt 函数加载后,ready 执行前,用油猴注入一个新的 closeIt 函数,函数里面啥也不干。但这样干有一个小瑕疵,就是不能保证每次都成功。
    ysc3839
        7
    ysc3839  
       2023-09-13 23:51:36 +08:00 via Android
    @Tsccai 并不是直接干掉,而是“然后调用原数”,所以并没有问题。
    ysc3839
        8
    ysc3839  
       2023-09-13 23:52:58 +08:00 via Android
    @Tsccai 如果 closeIt 是全局的话,似乎可以用 getter 和 setter 来阻止覆盖。
    另外还是建议给出原网站,以便判断最佳方案。
    Tsccai
        9
    Tsccai  
    OP
       2023-09-13 23:54:49 +08:00
    @kkk9 我这里测试结果是原网页的 ready 回调函数先执行,然后油猴注入的代码后执行。我只想让原页面中的 ready 回调函数不要执行
    Tsccai
        10
    Tsccai  
    OP
       2023-09-13 23:59:11 +08:00
    @ysc3839 原网页位于单位内网,不方便展示。不过 closeIt 这个函数确实在 window 对象下,我其实通过覆盖一个同名函数的方式也能大致实现,就是不大稳定
    Pipecraft
        11
    Pipecraft  
       2023-09-14 00:17:35 +08:00
    @Tsccai #10 如果 closeIt 是全局的,那就直接覆盖 closeIt ,不用管 $.ready 了。
    为了保证在 ready 之前执行,添加
    // @run-at document-start
    并监听 readystatechange 事件或使用 MutationObserver 来检查 closeIt 是否已加载并在 ready 执行期覆盖它。

    完整代码: https://pastebin.mozilla.org/CbxsMXbz
    Pipecraft
        12
    Pipecraft  
       2023-09-14 00:20:23 +08:00
    @Pipecraft #11 "并在 ready 执行期覆盖它" => "并在 ready 执行前覆盖它"
    Tsccai
        13
    Tsccai  
    OP
       2023-09-14 00:28:25 +08:00
    @Pipecraft 感觉这个方案不错,回头我试试看,感谢!
    Puteulanus
        14
    Puteulanus  
       2023-09-14 00:34:00 +08:00
    我问 ChatGPT 它这么说的:
    $(document).ready() 内部使用了原生 Javascript 的 document.addEventListener("DOMContentLoaded", callback) 或者 Internet Explorer 的 document.attachEvent("onreadystatechange", callback)。

    那在 @run-at document-start 的时候直接把 document 上的这两个函数劫持掉试试
    openmynet
        15
    openmynet  
       2023-09-14 00:34:54 +08:00
    ```js

    // @run-at document-start

    Object.defineProperty(window, "$", {
    get: () => {
    return (selector) => {
    const node = window._$(selector);
    if (node && selector instanceof Document) {
    node.ready = (callback) => {
    console.log("$ has been replaced");
    if (typeof callback == "function") {
    callback();
    }
    };
    }
    return node;
    };
    },
    set: (fn) => {
    window._$ = fn;
    },
    });

    ```
    openmynet
        16
    openmynet  
       2023-09-14 00:39:34 +08:00
    chnwillliu
        17
    chnwillliu  
       2023-09-14 08:08:44 +08:00 via Android
    为什么要覆盖这些?覆盖 $.fn.ready 不就行了?

    看来 jQuery 是真老了,没人知道了。

    $.fn.ready = function (){

    }
    Marlon
        18
    Marlon  
       2023-09-14 08:25:10 +08:00 via iPhone
    @vvhy 感谢,最近恰好遇到一个要阻止自动执行函数,试试提前注入,重写方法。
    Tsccai
        19
    Tsccai  
    OP
       2023-09-27 18:21:00 +08:00
    过了半个月终于是有空在单位的电脑上试一下了。
    首先,ready 这个函数还被其他 jQuery 的插件和脚本使用,所以 @chnwillliu 直接覆盖为一个空函数的方案并不可行。
    不过,我们可以在覆盖的这个函数内部对传入的回调函数`cb`进行过滤,检测到`cb.toString().indexOf('closeIt')>-1`时直接返回,否则则执行该回调函数即可。也不再需要去覆盖 closet()函数本身了。
    golangggg
        20
    golangggg  
       2024-04-08 21:49:42 +08:00
    @vvhy 大佬, 请问您说的设置开启即时注入 这个在哪里, 我没搜到资料,
    我目前的问题就是设置了 @run-at document-start 后 偶尔好用, 偶尔不好用,
    目标站, 在代码第一行就执行了 alert(); 我想抵消掉这个 alert
    vvhy
        21
    vvhy  
       2024-04-09 09:55:24 +08:00
    @golangggg #20 我用的是 tampermonkey ,设置里配置模式选择高级
    golangggg
        22
    golangggg  
       2024-04-09 13:50:54 +08:00
    @vvhy 非常感谢, 昨晚我自己摸索了一下 确实在高级里有一个注入模式 ,改成及时之后真的很有效
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3917 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 04:11 PVG 12:11 LAX 21:11 JFK 00:11
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86