7

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

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

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

loginwin位于undefined下面的代码中,尽管弹出窗口使用指定的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);
4

2 回答 2

6

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


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

  • window变量不引用页面的全局对象。相反,它指的是一个新的上下文,一个页面上的“层”。页面的 DOM 是完全可访问的。#执行环境

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

  • 对框架内容的访问受到页面同源策略的限制;您的扩展程序的权限不会放松政策。
  • frames[0]frames['frameName'],(通常指帧的包含全局window对象)是undefined.
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument返回document包含框架的对象,因为内容脚本可以访问页面的 DOM。此属性null适用于同源策略。
    • iframe.contentDocument.defaultView(指window与文档关联的对象)未定义
    • iframe.contentWindow未定义的。

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


备择方案

  • 在页面中注入代码,使其在页面的上下文中运行。注意:仅当您正在操作的页面可以信任时才使用此方法。要在注入脚本和内容脚本之间进行通信,您可以使用:

    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.
于 2012-08-05T10:10:37.943 回答
2

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

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

if (!loginWin)
    alert("You must first unblock popups and try again for this to work!");
于 2013-12-04T19:49:48.000 回答