javascript window.open 在 chrome 扩展中返回未定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11812786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 14:26:10  来源:igfitidea点击:

window.open returns undefined in chrome extension

javascriptgoogle-chromegoogle-chrome-extensionpopup

提问by user1566788

I have content script based Chrome extension. I initiate the sign in process through a popup window in the content script.

我有基于内容脚本的 Chrome 扩展。我通过内容脚本中的弹出窗口启动登录过程。

I open a popup window using the below code and then wait till its closed.

我使用下面的代码打开一个弹出窗口,然后等到它关闭。

However, I get an 'undefined' from window.openmethod. Does anybody know why this happens?

但是,我从window.open方法中得到一个“未定义” 。有人知道为什么会这样吗?

loginwinis undefinedin below code although the popup window opens up fine with the specified login_url. The code below is called from my content script.

loginwinundefined在下面的代码,虽然与指定的弹出窗口打开了罚款login_url。下面的代码是从我的内容脚本中调用的。

var loginWin = window.open(login_url, 'LoginWindow', "width=655,height=490");
console.log(loginWin);
// Check every 100 ms if the popup is closed.
var finishedInterval = setInterval(function() {
    console.log('checking if loginWin closed');
    if (loginWin.closed) {
        clearInterval(finishedInterval);
        console.log('popup is now closed');
        Backbone.history.navigate('index', true);
    }
}, 1000);

采纳答案by Rob W

Note: This answer is obsolete. window.open()in a Chrome extension always returns either null(when the popup is blocked) or a windowobject. The information below only applies to very old (2012) versions of Chrome.

注意:此答案已过时。window.open()在 Chrome 扩展程序中总是返回null(当弹出窗口被阻止时)或一个window对象。以下信息仅适用于非常旧 (2012) 版本的 Chrome。



Content scripts do not have any access to a page's global windowobject. For content scripts, the following applies:

内容脚本无权访问页面的全局window对象。对于内容脚本,以下适用:

  • The windowvariable does not refer to the page's global object. Instead, it refers to a new context, a "layer" over the page. The page's DOM is fully accessible. #execution-environment
  • window变量不引用页面的全局对象。相反,它指的是一个新的上下文,页面上的一个“层”。页面的 DOM 是完全可访问的。#执行环境

Given a document consisting of   <iframe id="frameName" src="http://domain/"></iframe>:

给定一个包含以下内容的文档   <iframe id="frameName" src="http://domain/"></iframe>

  • Access to the contents of a frame is restricted by the Same origin policyof the page; the permissions of your extension does not relax the policy.
  • frames[0]and frames['frameName'], (normally referring to the the frame's containing global windowobject) is undefined.
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocumentreturns a documentobject of the containing frame, because content scripts have access to the DOM of a page. This property is nullwhen the Same origin policy applies.
    • iframe.contentDocument.defaultView(refers to the windowobject associated with the document) is undefined.
    • iframe.contentWindowis undefined.
  • 对框架内容的访问受到页面同源策略的限制;您的扩展程序的权限不会放宽政策。
  • frames[0]frames['frameName'],(通常是指包含框架的全局window对象)是undefined
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument返回document包含框架的对象,因为内容脚本可以访问页面的 DOM。此属性null适用于同源策略。
    • iframe.contentDocument.defaultView(指window与文档关联的对象)是undefined
    • iframe.contentWindow未定义的

As you can see, window.open()does not return a Windowinstance (neither does window.opener, and so forth).

如您所见,window.open()不返回Window实例(也不返回window.opener,等等)。



Alternatives

备择方案

  • Inject the code in the page, so that it runs in the context of the page. Note: Only use this method if the page you're operating on can be trusted. To communicate between the injected script and the content script, you could use:

    var login_url = 'http://example.com/';
    var event_name = 'robwuniq' + Math.random().toString(16); // Unique name
    document.addEventListener(event_name, function localName() {
        document.removeEventListener(event_name, localName); // Clean-up
        // Your logic:
        Backbone.history.navigate('index', true);
    });
    // Method 2b: Inject code which runs in the context of the page
    var actualCode = '(' + function(login_url, event_name) {
        var loginWin = window.open(login_url, 'LoginWindow', "width=655,height=490");
        console.log(loginWin);
        // Check every 100 ms if the popup is closed.
        var finishedInterval = setInterval(function() {
            console.log('checking if loginWin closed');
            if (loginWin.closed) {
                clearInterval(finishedInterval);
                console.log('popup is now closed');
                // Notify content script
                var event = document.createEvent('Events');
                event.initEvent(event_name, false, false);
                document.dispatchEvent(event);
            }
        }, 1000);
    } + ')(' + JSON.stringify(login_url+'') + ', "' + event_name + '")';
    var script = document.createElement('script');
    script.textContent = actualCode;
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
    
  • Launch the window from the background page using window.open(). This returns a windowobject which has a reliable closedproperty. See the next bullet point for more details on the communication flow.

  • From the content script, pass a messageto the background page. In the background page, use chrome.windows.createto open a window. In the callback, assign an chrome.tabs.onRemovedand/or chrome.tabs.onUpdatedevent. When these event listeners are triggered, they should remove themselves, and notify the original caller (content script) using the sendResponsefunction of chrome.extension.onMessage.
  • 在页面中注入代码,使其在页面上下文中运行。注意:仅当您正在操作的页面可以信任时才使用此方法。要在注入的脚本和内容脚本之间进行通信,您可以使用:

    var login_url = 'http://example.com/';
    var event_name = 'robwuniq' + Math.random().toString(16); // Unique name
    document.addEventListener(event_name, function localName() {
        document.removeEventListener(event_name, localName); // Clean-up
        // Your logic:
        Backbone.history.navigate('index', true);
    });
    // Method 2b: Inject code which runs in the context of the page
    var actualCode = '(' + function(login_url, event_name) {
        var loginWin = window.open(login_url, 'LoginWindow', "width=655,height=490");
        console.log(loginWin);
        // Check every 100 ms if the popup is closed.
        var finishedInterval = setInterval(function() {
            console.log('checking if loginWin closed');
            if (loginWin.closed) {
                clearInterval(finishedInterval);
                console.log('popup is now closed');
                // Notify content script
                var event = document.createEvent('Events');
                event.initEvent(event_name, false, false);
                document.dispatchEvent(event);
            }
        }, 1000);
    } + ')(' + JSON.stringify(login_url+'') + ', "' + event_name + '")';
    var script = document.createElement('script');
    script.textContent = actualCode;
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
    
  • 使用window.open().从后台页面启动窗口。这将返回一个window具有可靠closed属性的对象。有关通信流程的更多详细信息,请参阅下一个要点。

  • 从内容脚本中,将消息传递后台页面。在后台页面中,用于chrome.windows.create打开一个窗口。在回调中,分配一个chrome.tabs.onRemoved和/或chrome.tabs.onUpdated事件。当这些事件监听器被触发时,应自行拆除,并通知使用原调用者(内容脚本)sendResponse的功能chrome.extension.onMessage

回答by ScottyB

In my case, Chrome was blocking the popup and the user had to unblock by clicking the "blocked popup" icon in the upper-right corner of the window. (They can also enable/disable exceptions under "Content settings..." in Chrome settings.)

就我而言,Chrome 阻止了弹出窗口,用户必须通过单击窗口右上角的“阻止的弹出窗口”图标来取消阻止。(他们还可以在 Chrome 设置中的“内容设置...”下启用/禁用例外。)

I would suggest adding some code after window.open() so that the user knows what to do. For example:

我建议在 window.open() 之后添加一些代码,以便用户知道该怎么做。例如:

if (!loginWin)
    alert("You must first unblock popups and try again for this to work!");