最近在研究一个古老的系统,想写一个油猴脚本。我发现页面中有这样的代码:
$(document).ready(
closeIt();
)
程序会在 dom 加载完后检查浏览器版本,不满足直接关闭页面窗口。 那么,油猴脚本能否拦截 ready 函数,不让其执行原来的程序呢?
1
kkk9 2023-09-13 18:25:08 +08:00
实践出真知!
```javascript (function() { 'use strict'; $(document).ready(function() { // ... 你自己的代码 } }) ``` |
2
kkk9 2023-09-13 18:25:50 +08:00
漏了一个) 记得自己补足
|
3
ysc3839 2023-09-13 18:31:52 +08:00 via Android
拦截 ready 肯定行呀,替换掉“$”,然后调用原函数,判断一下传入的参数是不是 document ,或者返回的对象有没有 ready 函数,有的话替换掉 ready 。
不过个人感觉从检查浏览器版本那下手会更好吧?建议能给原网页。 |
4
caomu 2023-09-13 19:11:32 +08:00 via Android
如果不是直接载入脚本,而是用浏览器扩展载入的话,主流的 gm 、tm 、vm 扩展应该都是支持设置脚本生效时间,默认是页面载入完成后,也可以手工改成载入开始时。
|
5
vvhy 2023-09-13 19:33:56 +08:00
用//@run-at document-start ,还不够快的话去设置开启即时注入
|
6
Tsccai OP @ysc3839 呃,因为网页其他代码还需要用 jQuery ,所以直接干掉$是不可取的。我是准备在原本的 closeIt 函数加载后,ready 执行前,用油猴注入一个新的 closeIt 函数,函数里面啥也不干。但这样干有一个小瑕疵,就是不能保证每次都成功。
|
8
ysc3839 2023-09-13 23:52:58 +08:00 via Android
@Tsccai 如果 closeIt 是全局的话,似乎可以用 getter 和 setter 来阻止覆盖。
另外还是建议给出原网站,以便判断最佳方案。 |
9
Tsccai OP @kkk9 我这里测试结果是原网页的 ready 回调函数先执行,然后油猴注入的代码后执行。我只想让原页面中的 ready 回调函数不要执行
|
10
Tsccai OP @ysc3839 原网页位于单位内网,不方便展示。不过 closeIt 这个函数确实在 window 对象下,我其实通过覆盖一个同名函数的方式也能大致实现,就是不大稳定
|
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 |
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 上的这两个函数劫持掉试试 |
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; }, }); ``` |
16
openmynet 2023-09-14 00:39:34 +08:00
|
17
chnwillliu 2023-09-14 08:08:44 +08:00 via Android
为什么要覆盖这些?覆盖 $.fn.ready 不就行了?
看来 jQuery 是真老了,没人知道了。 $.fn.ready = function (){ } |
19
Tsccai OP 过了半个月终于是有空在单位的电脑上试一下了。
首先,ready 这个函数还被其他 jQuery 的插件和脚本使用,所以 @chnwillliu 直接覆盖为一个空函数的方案并不可行。 不过,我们可以在覆盖的这个函数内部对传入的回调函数`cb`进行过滤,检测到`cb.toString().indexOf('closeIt')>-1`时直接返回,否则则执行该回调函数即可。也不再需要去覆盖 closet()函数本身了。 |
20
golangggg 254 天前
|