修改JavaScript中window.location.href会导致Greasemonkey无法关闭窗口吗?
问题解答
1. 权限丢失的原因
没错,就是修改window.location.href导致的——Firefox对window.close()的权限限制非常严格:只有通过脚本主动创建的窗口(比如用window.open()打开的新窗口),创建它的脚本才有资格调用window.close()关闭它。
你当前的窗口是用户手动打开或通过正常网页导航进入的,哪怕页面脚本修改了location.href跳转到应用协议,这个窗口的"创建者"依然不是你的Greasemonkey脚本,所以直接调用window.close()会被浏览器拦截。
2. 实现重定向+关闭窗口的解决方案
核心思路是:绕过原生location跳转,自己触发应用协议,再用技巧获取窗口关闭权限。这里提供两种可行方案:
方案一:拦截原页面的跳转(推荐)
用run-at: document-start让脚本在原页面代码之前运行,拦截它的location.href修改,自己触发应用后关闭窗口:
// ==UserScript== // @name 启动应用并自动关窗 // @namespace your-custom-namespace // @version 0.1 // @description 触发桌面应用后自动关闭当前浏览器窗口 // @match 你的目标网页完整URL // @run-at document-start // @grant none // ==/UserScript== // 拦截window.location.href的设置 const originalSetHref = Object.getOwnPropertyDescriptor(window.location.__proto__, 'href').set; Object.defineProperty(window.location, 'href', { set: function(value) { if (value.startsWith('app_protocol://')) { // 用隐藏iframe触发应用协议,避免页面跳转 const triggerFrame = document.createElement('iframe'); triggerFrame.style.display = 'none'; triggerFrame.src = value; document.documentElement.appendChild(triggerFrame); // 用技巧绕过关闭权限:模拟脚本创建当前窗口后关闭 setTimeout(() => { window.open('', '_self').close(); }, 500); return; } // 非应用协议的跳转正常执行 originalSetHref.call(this, value); } });
方案二:直接触发应用后关闭窗口
如果不需要拦截原页面的跳转,也可以直接在页面加载后自己触发应用,再用同样的关闭技巧:
// ==UserScript== // @name 启动应用并自动关窗 // @namespace your-custom-namespace // @version 0.1 // @description 触发桌面应用后自动关闭当前浏览器窗口 // @match 你的目标网页完整URL // @run-at document-idle // @grant none // ==/UserScript== // 触发应用协议 const triggerFrame = document.createElement('iframe'); triggerFrame.style.display = 'none'; triggerFrame.src = 'app_protocol:///url.code'; document.body.appendChild(triggerFrame); // 延迟关闭,确保应用启动请求已发送 setTimeout(() => { window.open('', '_self').close(); }, 500);
注意事项
window.open('', '_self').close()是Firefox上常用的权限绕过技巧,但如果用户浏览器禁用了弹出窗口,这个方法可能失效,需要提醒用户调整对应设置。- 延迟时间可以根据实际情况调整(比如300-1000ms),保证应用启动请求已经被浏览器处理,再关闭窗口。
内容的提问来源于stack exchange,提问作者bjb
相关产品推荐
相关产品推荐

