迁移Firefox30前Greasemonkey脚本至GM4+:如何替换unsafeWindow并获取页面jQuery?
Greasemonkey 4+ 迁移:获取页面jQuery & 替换unsafeWindow指南
嘿,我帮你梳理下GM4+迁移时遇到的这个问题——毕竟GM从旧版本到4+的沙盒变化确实坑了不少人!
为什么旧方法失效了?
GM4+采用了严格的内容脚本沙盒,脚本运行的window和页面本身的window完全是两个独立环境。旧代码里的unsafeWindow.jQuery能直接拿页面jQuery,是因为unsafeWindow直接指向页面的全局对象,但GM4+默认禁用了这个权限;而你试的window.jQuery,拿的是脚本沙盒里的window,自然找不到页面的jQuery,所以会报ReferenceError。
解决方案1:用unsafeWindow(简单直接,需权限)
如果你能接受少量安全风险(毕竟unsafeWindow会让脚本直接接触页面环境),这是最快的方法:
- 在脚本开头的元数据里添加权限声明:
(如果之前没加// @grant unsafeWindow@grant,GM会启用"无权限模式",此时unsafeWindow不可用) - 然后就可以像旧版本一样获取jQuery:
var $ = unsafeWindow.jQuery; // 测试下是否可用 console.log('页面jQuery版本:', $.fn.jquery);
解决方案2:安全注入获取(推荐,无高权限依赖)
如果不想用unsafeWindow(避免页面脚本篡改全局对象带来的风险),可以通过向页面注入脚本,让页面主动把jQuery传递给GM脚本:
// 步骤1:向页面注入一个小脚本,获取jQuery并通过postMessage发送 const injectScript = document.createElement('script'); injectScript.textContent = ` // 这段代码在页面环境中执行,能直接拿到页面的jQuery const pageJQuery = window.jQuery; // 向GM脚本发送消息,携带jQuery对象 window.postMessage({ type: 'GM_GET_JQUERY', jquery: pageJQuery }, window.location.origin); `; document.head.appendChild(injectScript); injectScript.remove(); // 注入后立即移除脚本标签 // 步骤2:GM脚本监听消息,接收jQuery window.addEventListener('message', function handleJQueryMessage(event) { // 验证消息来源和类型,避免恶意消息 if (event.origin !== window.location.origin || event.data.type !== 'GM_GET_JQUERY') return; const $ = event.data.jquery; // 现在你就可以正常使用页面的jQuery了! console.log('成功获取页面jQuery:', $); // 记得移除监听,避免重复接收 window.removeEventListener('message', handleJQueryMessage); });
这种方法完全在沙盒规则内操作,安全性更高,也能避免部分网站对unsafeWindow的限制。
关于替换unsafeWindow的通用方法
除了获取jQuery,如果你之前用unsafeWindow访问其他页面全局变量,GM4+里有两种替代思路:
- 场景1:只读访问页面全局变量:用
unsafeWindow(需加@grant unsafeWindow)或者window.wrappedJSObject(Firefox专属,无需额外权限),比如unsafeWindow.pageGlobalVar。 - 场景2:需要和页面脚本交互:推荐用上面的
postMessage方式,或者使用GM_exportFunction把GM脚本的函数暴露给页面,再让页面调用(需要@grant GM_exportFunction权限)。比如:// GM脚本里定义函数 function gmFunction(data) { console.log('页面传来的数据:', data); return 'GM脚本返回的结果'; } // 暴露给页面 GM_exportFunction(gmFunction, unsafeWindow, { defineAs: 'gmFunction' }); // 页面脚本就可以调用window.gmFunction()了
内容的提问来源于stack exchange,提问作者NobleUplift
相关产品推荐
相关产品推荐

