从window.open返回一个值

des*_*lsj 15 javascript google-chrome showmodaldialog

我们最近发现Chrome不再支持window.showModalDialog,这是有问题的,因为我们的企业应用程序使用此方法.

显然,有一个短期解决方法可以让你恢复showModalDialog,但它涉及修改注册表,这对我们普通用户来说太复杂(而且有风险).因此,我不是这种解决方法的忠实粉丝.

长期解决方案显然是删除对这个过时方法的所有调用,并用一个方便的jQuery插件替换它们(例如VistaPrint的Skinny Modal Dialog插件.顺便提一句其他建议也是如此).

我们使用模态对话框的典型场景是在执行无法撤消的操作之前询问用户是/否确认,要求用户在继续操作之前同意条款和条件等.通常情况下onclick事件为"是"或模态对话框中的"确定"按钮如下所示:

window.returnValue = true;
window.close();
Run Code Online (Sandbox Code Playgroud)

同样,"取消"或"否"按钮如下所示:

window.returnValue = false;
window.close();
Run Code Online (Sandbox Code Playgroud)

我们可以从对话框中返回一个值的事实非常方便,因为它允许"父"窗口被通知用户是否单击了"确定"或"取消"按钮,如下所示:

var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
    ... proceed ...
}
Run Code Online (Sandbox Code Playgroud)

我要提到的关于showModalDialog的最后一件事是,即使对话框中显示的文档来自不同的域,它也能很好地工作.让我们的javascript从http://the-client.com运行是很常见的,但"服务条款"网页来自http://the-enterprise-vendor.com

我需要一个临时解决方案,我可以在我们处理长期解决方案时尽快部署.这是我的标准:

  • 现有JavaScript中的代码更改最少
  • 弹出窗口必须能够将值返回给"父".通常这个值是布尔值,但它可以是任何简单类型(例如:string,int等)
  • 即使内容的URL来自不同的域,解决方案也必须正常工作

这是我到目前为止所拥有的:

1)在我的JavaScript中添加以下方法:

function OpenDialog(url, width, height, callback)
{
    var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
    var timer = setInterval(function ()
    {
        if (win.closed)
        {
            clearInterval(timer);
            var returnValue = win.returnValue;
            callback(returnValue);
        }
    }, 500);
}
Run Code Online (Sandbox Code Playgroud)

正如您在此方法中所看到的,我尝试通过隐藏菜单和工具栏使弹出窗口看起来尽可能类似于对话框,我每隔500毫秒设置一次时间来检查窗口是否已被用户关闭如果是这样,请获取'returnValue'并调用回调.

2)用以下内容替换对showModalDialog的所有调用:

OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
    if (termsOfServiceAccepted)
    {
        ... proceed ....
    }
});
Run Code Online (Sandbox Code Playgroud)

该方法的第四个参数是回调,其中我检查用户是否在允许她继续之前单击了"确定"按钮.

我知道这是一个很长的问题,但基本上归结为:

  1. 您如何看待我提出的解决方案?
  2. 特别是,你认为我能从一个用window.open打开的窗口中获取returnValue吗?
  3. 您可以建议的其他替代方案吗?

Aug*_*nta 17

我有两个想法可以帮助你,但第一个与CORS绑定,所以你将无法从不同的域使用它,至少你可以访问这两个服务并配置它们.

第一个想法:

第一个与本机api有关.您可以在父窗口上创建一个像这样的全局函数:

window.callback = function (result) {
    //Code
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它会收到一个结果参数,该参数可以保存您需要的布尔值.您可以使用相同的旧window.open(url)函数打开弹出窗口.弹出窗口的onlick事件处理程序可能如下所示:

function() {
    //Do whatever you want.
    window.opener.callback(true); //or false
}
Run Code Online (Sandbox Code Playgroud)

第二个想法:解决问题

我得到的另一个想法是使用这个其他本机api在弹出窗口解析时触发父窗口上的事件(更好地称为跨文档消息传递).所以你可以从父窗口执行此操作:

window.onmessage = function (e) {
    if (e.data) {
        //Code for true
    } else {
        //Code for false
    }
};
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您正在侦听此窗口上的任何已发布消息,并检查附加到消息的数据是否为(用户在弹出窗口中单击"确定")或false(用户在弹出窗口中单击"取消").

在弹出窗口中,您应该将消息发布到父窗口,在对应时附加truefalse值:

window.opener.postMessage(true, '*'); //or false
Run Code Online (Sandbox Code Playgroud)

我认为这个解决方案完全符合您的需求.

编辑 我写道,第二个解决方案也与CORS绑定,但深入挖掘我意识到跨文档消息传递与CORS无关