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

2023-09-13 16:30:14 +08:00
 Tsccai

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

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

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

3013 次点击
所在节点    jQuery
22 条回复
kkk9
2023-09-13 18:25:08 +08:00
实践出真知!

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

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

$.fn.ready = function (){

}
Marlon
2023-09-14 08:25:10 +08:00
@vvhy 感谢,最近恰好遇到一个要阻止自动执行函数,试试提前注入,重写方法。
Tsccai
2023-09-27 18:21:00 +08:00
过了半个月终于是有空在单位的电脑上试一下了。
首先,ready 这个函数还被其他 jQuery 的插件和脚本使用,所以 @chnwillliu 直接覆盖为一个空函数的方案并不可行。
不过,我们可以在覆盖的这个函数内部对传入的回调函数`cb`进行过滤,检测到`cb.toString().indexOf('closeIt')>-1`时直接返回,否则则执行该回调函数即可。也不再需要去覆盖 closet()函数本身了。
golangggg
254 天前
@vvhy 大佬, 请问您说的设置开启即时注入 这个在哪里, 我没搜到资料,
我目前的问题就是设置了 @run-at document-start 后 偶尔好用, 偶尔不好用,
目标站, 在代码第一行就执行了 alert(); 我想抵消掉这个 alert

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/973443

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX