背景

之前有个项目是 jsp 的,之前都是在 IE 浏览器上运行,现在要将这个项目做兼容性改造(信创),需要兼容谷歌。所以需要将项目中的公共弹框给改掉,而项目中模态框基本上都是用的 showModalDialog

介绍 showModalDialog

showModalDialog 是微软在早期版本的(IE)中引入的一个方法,用于创建模态对话框。不过在现代浏览器中已经不再支持这个方法了。

用法(参考MDN):

returnVal = window.showModalDialog(uri[, arguments][, options]);
  • returnVal 模态框的返回值。
  • uri 要在模态对话框中打开的页面 URI。
  • arguments 可选变量。可以通过该参数将需要的值传入对话框。
  • options 可选字符串参数。用于设置对话框打开的样式,使用一个或多个逗号分隔。

缺点:

  • 现代浏览器不支持
  • 模态框没有遮罩层,无法做到处理完模态框再处理父级页面

重写

步骤
  • 使用 iframe 代替模态框中的内容包裹层(传递给模态框的uri是后台一个接口,接口返回一个jsp页面,模态框展示的就是这个页面,而 iframe 可以用来嵌入内容)
  • 仍然支持 showModalDialog 的三个参数以及返回值给父页面
  • 添加遮罩层,关闭模态框之前不能点击并处理父级页面
  • 重写关闭模态框的方法(之前模态框关闭方法是 window.close
编写函数

1、定义默认样式

//定义默认样式
var DIALOG_CLASS = "modernShowDialog"; //弹框类名
var SUB_STYLE =
"position:absolute;top:50%;left:50%;margin-1eft:-50%;margin-top:150px;background:#fff;border-radius: 4px;";
var IFAME_STYLE = "width:100%;border: none;height: 70%;";
var dialog_header_style =
"width:100%;height:32px;font-size:14px;line-height:34px;";

2、获取项目顶层的 document,弹框要覆盖所有页面,必须添加到顶层 window

function showModalDialog(pageUrl, comeInParams, iframeStyle) {
//获取传进来的宽高
iframeStyle = iframeStyle.replace(/dialogwidth/g, "width");
iframeStyle = iframeStyle.replace(/dialogHeight/g, "height"); //获取项目顶层的 document
var topDoc = window.top.document;
var topDocBody = window.top.document.body;
var mainFrameSet = topDoc.querySelector("#setMain"); // 最终生成的模态框会插入到 mainFrameSetParent 中
var mainFrameSetParent = mainFrameSet.parentNode; return new Promise((resolve, reject) => {
//···
})
}

这里返回一个 promise ,返回值也会通过 resolve 返回给父级页面,父页面通过 .then 或者 await 接收。

3、创建弹框盒子,弹框headeriframe区域,footer,添加遮罩层

return new Promise((resolve, reject) => {
//创建弹框盒子,添加遮罩层
var dialog = document.createElement("div");
dialog.className = DIALOG_CLASS + Date.now();
dialog.style = DIALOG_STYLE + ";width:" + topDocBody.clientwidth + "px;"; //创建弹框里面用来包裹iframe的 div
var dialogBody = document.createElement("div");
dialogBody.className = "dialogBody";
var marginLeft = parseFloat(
iframeStyle.match(/width\:(\d)+px;/g)[0].replace("width:", "")
);
var marginTop = parseFloat(
iframeStyle.match(/height\:(\d)+px;/g)[0].replace("height:", "")
);
dialogBody.style =
SUB_STYLE +
";margin-left:-" +
marginLeft / 2 +
"px;margin-top:-" +
marginTop / 2 +
"px;"; //创建 header
var header = document.createElement("div");
header.className = "dialog_header";
header.style = dialog_header_style;
var headerBtn = document.createElement("div");
headerBtn.style =
"cursor:pointer;text-align:right;padding-right:10px;font-size: 20px;user-select: none;";
headerBtn.textContent = "x";
headerBtn.onclick = function () {
mainFrameSetParent.removeChild(dialog);
};
header.appendChild(headerBtn); //创建 iframe 包裹层
var iframe = document.createElement("iframe");
iframe.src = pageUrl;
iframe.className = "modernDialogIframe";
iframe.style = IFAME_STYLE + iframeStyle;
iframe.destroy = function (returnValue) {
resolve(returnValue);
mainFrameSetParent.removeChild(dialog);
removeStorageClass();
};
dialogBody.appendChild(header);
dialogBody.appendChild(iframe);
dialog.appendChild(dialogBody); var removeStorageClass = function () {
var existClass = sessionStorage.getItem("dialogClass");
if (existClass) {
sessionStorage.setItem(
"dialogClass",
existClass.split(",").pop().join(",")
);
}
}; //将创建好的弹框插入顶层 document
mainFrameSetParent.appendChild(dialog); // 通过sessionStorage 存储当前显示的弹框的类名,
//给某些特定页面(通过windbw.close 关闭不了的页面,因为里面的window可能表单操作刷新了window)使用
var session = sessionStorage.getItem('dialogClass')
sessionStorage.setItem('dialogClass',session ? (session + ',' + dialog.className) : dialog.className)

需要注意的是,上面定义了 iframe.destroyremoveStorageClass 方法用来给某些特殊页面用的,那些特殊页面因为表单操作刷新了当前 window,导致调用不到了我们的重写的 close 方法。所以只能那些页面中处理完业务后手动调用 destroy 方法关闭模态框。

4、iframe加载完毕后,重写模态框的关闭方法

var modernDialogIframe = topDoc.querySelector(
"." + dialog.className + " .modernDialogIframe"
);
var tempValue = null;
//监听 iframe 包裹的目标页面的加载情况
modernDialogIframe.contentwindow.addEventListener("load", function () {
this.dialogArguments = comeInParams;
this.oldClose = this.close;
//重写当前页面的 window.close
this.close = function () {
// returnValue 是业务页面中定义的全局变量
tempValue = this.returnValue;
setTimeout(function () {
resolve(tempValue);
}, 10);
mainFrameSetParent.removeChild(dialog);
removeStorageClass();
this.oldClose();
};
});
完整代码
//定义默认样式
var DIALOG_CLASS = "modernShowDialog";
var SUB_STYLE =
"position:absolute;top:50%;left:50%;margin-1eft:-50%;margin-top:150px;background:#fff;border-radius: 4px;";
var IFAME_STYLE = "width:100%;border: none;height: 70%;";
var dialog_header_style =
"width:100%;height:32px;font-size:14px;line-height:34px;"; /**
* 模拟 IE 的 showModalDialog 方法,同样接收三个参数;
* pageUrl 表示要显示的页面地址
* comeInParams 表示传进目标页面的参数
* iframeStyle 表示自定义页面样式,比如宽高
**/ function showModalDialog(pageUrl, comeInParams, iframeStyle) {
iframeStyle = iframeStyle.replace(/dialogwidth/g, "width");
iframeStyle = iframeStyle.replace(/dialogHeight/g, "height"); //获取项目顶层的 document,弹框显示需要覆盖顶层页面
var topDoc = window.top.document;
var mainFrameSet = topDoc.querySelector("#setMain");
var mainFrameSetParent = mainFrameSet.parentNode;
var topDocBody = window.top.document.body; return new Promise((resolve, reject) => {
//创建弹框盒子,添加遮罩层
var dialog = document.createElement("div");
dialog.className = DIALOG_CLASS + Date.now();
dialog.style = DIALOG_STYLE + ";width:" + topDocBody.clientwidth + "px;"; //创建弹框里面用来包裹iframe的 div
var dialogBody = document.createElement("div");
dialogBody.className = "dialogBody";
var marginLeft = parseFloat(
iframeStyle.match(/width\:(\d)+px;/g)[0].replace("width:", "")
);
var marginTop = parseFloat(
iframeStyle.match(/height\:(\d)+px;/g)[0].replace("height:", "")
);
dialogBody.style =
SUB_STYLE +
";margin-left:-" +
marginLeft / 2 +
"px;margin-top:-" +
marginTop / 2 +
"px;"; //创建 header
var header = document.createElement("div");
header.className = "dialog_header";
header.style = dialog_header_style;
var headerBtn = document.createElement("div");
headerBtn.style =
"cursor:pointer;text-align:right;padding-right:10px;font-size: 20px;user-select: none;";
headerBtn.textContent = "x";
headerBtn.onclick = function () {
mainFrameSetParent.removeChild(dialog);
};
header.appendChild(headerBtn); //创建 iframe 包裹层
var iframe = document.createElement("iframe");
iframe.src = pageUrl;
iframe.className = "modernDialogIframe";
iframe.style = IFAME_STYLE + iframeStyle;
iframe.destroy = function (returnValue) {
resolve(returnValue);
mainFrameSetParent.removeChild(dialog);
removeStorageClass();
};
dialogBody.appendChild(header);
dialogBody.appendChild(iframe);
dialog.appendChild(dialogBody);
var removeStorageClass = function () {
var existClass = sessionStorage.getItem("dialogClass");
if (existClass) {
sessionStorage.setItem(
"dialogClass",
existClass.split(",").pop().join(",")
);
}
}; //将创建好的弹框插入顶层 document
mainFrameSetParent.appendChild(dialog);
// 通过sessionStorage 存储当前显示的弹框的类名,给某些特定页面(通过windbw.close 关闭不了的页面,因为里面的window可能表单操作刷新了window)使用
var session = sessionStorage.getItem('dialogClass')
sessionStorage.setItem('dialogClass',session ? (session + ',' + dialog.className) : dialog.className) var modernDialogIframe = topDoc.querySelector(
"." + dialog.className + " .modernDialogIframe"
); var tempValue = null;
//监听 iframe 包裹的目标页面的加载情况
modernDialogIframe.contentwindow.addEventListener("load", function () {
this.dialogArguments = comeInParams;
this.oldClose = this.close;
//重写当前页面的 window.close
this.close = function () {
tempValue = this.returnValue;
setTimeout(function () {
resolve(tempValue);
}, 10);
mainFrameSetParent.removeChild(dialog);
removeStorageClass();
this.oldClose();
};
});
});
}

重写IE的showModalDialog模态框以兼容现代浏览器的更多相关文章

  1. 教你使用HTML5原生对话框元素,轻松创建模态框组件

    HTML 5.2草案加入了新的dialog元素.但是是一种实验技术. 以前,如果我们想要构建任何形式的模式对话框或对话框,我们需要有一个背景,一个关闭按钮,将事件绑定在对话框中的方式安排我们的标记,找 ...

  2. 模态框在IE下的问题,即position:fixed在IE下不兼容的处理方式

    项目中遇到的问题,模态框在IE下总出现如图所示双层遮罩框,经排查发现是由于bootstrap里写的modal的样式里position:fixed不兼容IE的原因,导致铺不满整个窗口. 解决方案:在项目 ...

  3. Bootstrap模态框(MVC)

    BZ这篇博客主要是为大家介绍一下MVC如何弹出模态框.本文如果有什么不对的地方,希望大神们多多指教,也希望和我一样的小菜多多学习.BZ在这里谢过各位. 首先要在页面加上一个点击事件: @Html.Ac ...

  4. bootstrap模态框和select2合用时input无法获取焦点

    在bootstrap的模态框里使用select2插件,会导致select2里的input输入框没有办法获得焦点,没有办法输入. 解决方法: 1. 把页面中的  tabindex="-1&qu ...

  5. bootstrap日期控件在火狐下的模态框中选择时间下拉菜单无效的解决办法

    今天收到程序组提交的一个兼容BUG,在火狐中使用模态框加载日期控件时选择时间下拉菜单没有效果(不能点击),而在谷歌中却是好的, 排错思路:1,在当前页面主层放置一个时间控件,测试通过 2,在ajax加 ...

  6. jQuery初识之选择器、样式操作和筛选器(模态框和菜单示例)

    一.jQuery 1.介绍 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架). jQuery设计的 ...

  7. bootstrap弹出模态框会给body加padding的解决方法

    bootstrap弹出模态框会给body加padding,导致页面缩放的解决方法: 在页面或是css文件里加上($paddingSize为less变量,需要改成像素或是其他单位,如12px,1rem) ...

  8. javascript 利用冒泡机制显示与隐藏模态框

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. IE中window的模态框与返回值

    window.returnValue是javascript中html的window对象的属性,目的是返回窗口值,当用window.showModalDialog函数打开一个IE的模态窗口时,用于返回窗 ...

  10. bootstrap模态框input不能获取焦点并编辑【转】

    Bootstrap模态框时input标签[日期控件也有这样的问题]不能编辑的问题,下面是我的解决方法: 1.将下图中框出来的属性删掉即可: 2.兼容火狐浏览器,笔者在火狐中还是不能编辑,去掉下图属性即 ...

随机推荐

  1. Laravel11 从0开发 Swoole-Reverb 扩展包(四) - 触发一个广播事件到reverb服务之后是如何转发给前端订阅的呢(下)?

    前情提要 上一篇我们讲到了reverb服务的通信上下文和路由处理,路由实现了pusher关联的几种请求.那么这一篇我们主要来讲混响服务Server 混响 Server 负责基于 ReactPHP 的 ...

  2. k8s dial tcp 127.0.0.1:6443: connect: connection refused排查流程及解决思路

    前言 k8s 集群中,使用 kubelet 报错,如下: The connection to the server 127.0.0.1:6443 was refused - did you speci ...

  3. Docker镜像介绍

    一.Docker镜像介绍 镜像是Docker的三大核心概念之一. Docker运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker会尝试先从默认的镜像仓库下载(默认使用Docker Hu ...

  4. CSS那些事读书笔记-2

    背景 作为一个后端开发,曾经尝试过学习前端,但是总觉不得要领,照猫画虎,而公司里又有专业的前端开发,工作中几乎接触不到实际的前端任务,所以前端的技能田野一直是一片荒芜.但是笔者深知前端的技能对找工作和 ...

  5. Windows桌面应用自动更新解决方案SharpUpdater5发布

    SharpUpdater是什么 SharpUpdater是一套C#桌面应用自动更新解决方案.基本上,所有自动更新程序的原理都一样:生成一份文件清单,将本地清单与云上清单对比后进行全量更新或增量更新.本 ...

  6. 集合体系介绍、collection的使用--java进阶day09

    1.集合体系结构 我们要学习的集合大体分为两种,一种是单列集合,一种是双列集合 2.单列集合 单列集合又分为两个派系,分别为list接口和set接口,这两个接口皆是collection接口的子接口 3 ...

  7. 【Git】工作流

    Git 工作流 概念 在项目开发过程中使用 Git 的方式 分类 集中式工作流 像 SVN 一样,集中式工作流以中央仓库作为项目所有修改的单点实体.所有 修改都提交到 Master 这个分支上. 这种 ...

  8. HTML5 定时通知

    通过setInterval()和Notification来实现定时通知功能. demo <script> window.onload = function () { //每10秒弹出一个桌 ...

  9. jmeter性能测试案例:电商系统并发订单测试

    场景描述:本案例主要实现多用户同时提交订单,以检测系统对瞬时压力的响应情况.具体流程包括用户登录-添加商品-提交订单.涉及多个接口联动和参数处理,步骤如下: 第一步,登录用户 1.新建"下订 ...

  10. CSS横向滚动

    Flex版本 .super { display: flex; width: 100%; overflow-x: scroll; white-space: nowrap; } .sub { width: ...