19

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

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

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

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

window.returnValue = true;
window.close();

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

window.returnValue = false;
window.close();

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

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

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

我需要一个临时解决方案,以便在我们制定长期解决方案时尽快部署。这是我的标准:

  • 现有 JavaScript 中的最小代码更改
  • 弹出窗口必须能够向“父级”返回一个值。通常这个值是一个布尔值,但它可以是任何简单的类型(例如:字符串、整数等)
  • 即使内容的 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);
}

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

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

OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
    if (termsOfServiceAccepted)
    {
        ... proceed ....
    }
});

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

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

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

1 回答 1

24

我有两个想法可以帮助您,但第一个与 CORS 相关,因此您将无法从不同的域使用它,至少您可以访问这两个服务并配置它们。

第一个想法:

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

window.callback = function (result) {
    //Code
}

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

function() {
    //Do whatever you want.
    window.opener.callback(true); //or false
}

第二个想法:解决问题

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

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

通过这种方式,您正在收听此窗口上发布的任何消息,并检查附加到消息的数据是(用户在弹出窗口中单击确定)还是(用户在弹出窗口中单击取消)。

在弹出窗口中,您应该向父窗口发布一条消息,并在对应时附加一个truefalse值:

window.opener.postMessage(true, '*'); //or false

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

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

于 2014-09-10T22:48:14.150 回答