找回密码
 立即注册
首页 业界区 业界 重写IE的showModalDialog模态框以兼容现代浏览器 ...

重写IE的showModalDialog模态框以兼容现代浏览器

靳夏萱 2025-6-8 19:05:02
背景

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

showModalDialog 是微软在早期版本的(IE)中引入的一个方法,用于创建模态对话框。不过在现代浏览器中已经不再支持这个方法了。
用法(参考MDN):
  1. returnVal = window.showModalDialog(uri[, arguments][, options]);
复制代码

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

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

步骤


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

1、定义默认样式
  1. //定义默认样式
  2. var DIALOG_CLASS = "modernShowDialog";  //弹框类名
  3. var SUB_STYLE =
  4. "position:absolute;top:50%;left:50%;margin-1eft:-50%;margin-top:150px;background:#fff;border-radius: 4px;";
  5. var IFAME_STYLE = "width:100%;border: none;height: 70%;";
  6. var dialog_header_style =
  7. "width:100%;height:32px;font-size:14px;line-height:34px;";
复制代码
2、获取项目顶层的 document,弹框要覆盖所有页面,必须添加到顶层 window 中
  1. function showModalDialog(pageUrl, comeInParams, iframeStyle) {
  2.     //获取传进来的宽高
  3.     iframeStyle = iframeStyle.replace(/dialogwidth/g, "width");
  4.     iframeStyle = iframeStyle.replace(/dialogHeight/g, "height");
  5.     //获取项目顶层的 document
  6.     var topDoc = window.top.document;
  7.     var topDocBody = window.top.document.body;
  8.     var mainFrameSet = topDoc.querySelector("#setMain");
  9.    
  10.     // 最终生成的模态框会插入到 mainFrameSetParent 中
  11.     var mainFrameSetParent = mainFrameSet.parentNode;
  12.    
  13.     return new Promise((resolve, reject) => {
  14.         //···
  15.     })
  16. }
复制代码
这里返回一个 promise ,返回值也会通过 resolve 返回给父级页面,父页面通过 .then 或者 await 接收。
3、创建弹框盒子,弹框header,iframe区域,footer,添加遮罩层
  1. return new Promise((resolve, reject) => {
  2.     //创建弹框盒子,添加遮罩层
  3.     var dialog = document.createElement("div");
  4.     dialog.className = DIALOG_CLASS + Date.now();
  5.     dialog.style = DIALOG_STYLE + ";width:" + topDocBody.clientwidth + "px;";
  6.     //创建弹框里面用来包裹iframe的 div
  7.     var dialogBody = document.createElement("div");
  8.     dialogBody.className = "dialogBody";
  9.     var marginLeft = parseFloat(
  10.       iframeStyle.match(/width\:(\d)+px;/g)[0].replace("width:", "")
  11.     );
  12.     var marginTop = parseFloat(
  13.       iframeStyle.match(/height\:(\d)+px;/g)[0].replace("height:", "")
  14.     );
  15.     dialogBody.style =
  16.       SUB_STYLE +
  17.       ";margin-left:-" +
  18.       marginLeft / 2 +
  19.       "px;margin-top:-" +
  20.       marginTop / 2 +
  21.       "px;";
  22.     //创建 header
  23.     var header = document.createElement("div");
  24.     header.className = "dialog_header";
  25.     header.style = dialog_header_style;
  26.     var headerBtn = document.createElement("div");
  27.     headerBtn.style =
  28.       "cursor:pointer;text-align:right;padding-right:10px;font-size: 20px;user-select: none;";
  29.     headerBtn.textContent = "x";
  30.     headerBtn.onclick = function () {
  31.       mainFrameSetParent.removeChild(dialog);
  32.     };
  33.     header.appendChild(headerBtn);
  34.     //创建 iframe 包裹层
  35.     var iframe = document.createElement("iframe");
  36.     iframe.src = pageUrl;
  37.     iframe.className = "modernDialogIframe";
  38.     iframe.style = IFAME_STYLE + iframeStyle;
  39.     iframe.destroy = function (returnValue) {
  40.       resolve(returnValue);
  41.       mainFrameSetParent.removeChild(dialog);
  42.       removeStorageClass();
  43.     };
  44.     dialogBody.appendChild(header);
  45.     dialogBody.appendChild(iframe);
  46.     dialog.appendChild(dialogBody);
  47.    
  48.     var removeStorageClass = function () {
  49.       var existClass = sessionStorage.getItem("dialogClass");
  50.       if (existClass) {
  51.         sessionStorage.setItem(
  52.           "dialogClass",
  53.           existClass.split(",").pop().join(",")
  54.         );
  55.       }
  56.     };
  57.    
  58.     //将创建好的弹框插入顶层 document
  59.     mainFrameSetParent.appendChild(dialog);
  60.    
  61.     // 通过sessionStorage 存储当前显示的弹框的类名,
  62.     //给某些特定页面(通过windbw.close 关闭不了的页面,因为里面的window可能表单操作刷新了window)使用
  63.     var session = sessionStorage.getItem('dialogClass')
  64.     sessionStorage.setItem('dialogClass',session ? (session + ',' + dialog.className) : dialog.className)
复制代码
需要注意的是,上面定义了 iframe.destroy 和 removeStorageClass 方法用来给某些特殊页面用的,那些特殊页面因为表单操作刷新了当前 window,导致调用不到了我们的重写的 close 方法。所以只能那些页面中处理完业务后手动调用 destroy 方法关闭模态框。
4、iframe加载完毕后,重写模态框的关闭方法
  1. var modernDialogIframe = topDoc.querySelector(
  2.   "." + dialog.className + " .modernDialogIframe"
  3. );
  4. var tempValue = null;
  5. //监听 iframe 包裹的目标页面的加载情况
  6. modernDialogIframe.contentwindow.addEventListener("load", function () {
  7.   this.dialogArguments = comeInParams;
  8.   this.oldClose = this.close;
  9.   //重写当前页面的 window.close
  10.   this.close = function () {
  11.     // returnValue 是业务页面中定义的全局变量
  12.     tempValue = this.returnValue;
  13.     setTimeout(function () {
  14.       resolve(tempValue);
  15.     }, 10);
  16.     mainFrameSetParent.removeChild(dialog);
  17.     removeStorageClass();
  18.     this.oldClose();
  19.   };
  20. });
复制代码
完整代码
  1. //定义默认样式
  2. var DIALOG_CLASS = "modernShowDialog";
  3. var SUB_STYLE =
  4. "position:absolute;top:50%;left:50%;margin-1eft:-50%;margin-top:150px;background:#fff;border-radius: 4px;";
  5. var IFAME_STYLE = "width:100%;border: none;height: 70%;";
  6. var dialog_header_style =
  7. "width:100%;height:32px;font-size:14px;line-height:34px;";
  8. /**
  9. * 模拟 IE 的 showModalDialog 方法,同样接收三个参数;
  10. * pageUrl 表示要显示的页面地址
  11. * comeInParams 表示传进目标页面的参数
  12. * iframeStyle 表示自定义页面样式,比如宽高
  13. **/
  14. function showModalDialog(pageUrl, comeInParams, iframeStyle) {
  15.   iframeStyle = iframeStyle.replace(/dialogwidth/g, "width");
  16.   iframeStyle = iframeStyle.replace(/dialogHeight/g, "height");
  17.   //获取项目顶层的 document,弹框显示需要覆盖顶层页面
  18.   var topDoc = window.top.document;
  19.   var mainFrameSet = topDoc.querySelector("#setMain");
  20.   var mainFrameSetParent = mainFrameSet.parentNode;
  21.   var topDocBody = window.top.document.body;
  22.   return new Promise((resolve, reject) => {
  23.     //创建弹框盒子,添加遮罩层
  24.     var dialog = document.createElement("div");
  25.     dialog.className = DIALOG_CLASS + Date.now();
  26.     dialog.style = DIALOG_STYLE + ";width:" + topDocBody.clientwidth + "px;";
  27.     //创建弹框里面用来包裹iframe的 div
  28.     var dialogBody = document.createElement("div");
  29.     dialogBody.className = "dialogBody";
  30.     var marginLeft = parseFloat(
  31.       iframeStyle.match(/width\:(\d)+px;/g)[0].replace("width:", "")
  32.     );
  33.     var marginTop = parseFloat(
  34.       iframeStyle.match(/height\:(\d)+px;/g)[0].replace("height:", "")
  35.     );
  36.     dialogBody.style =
  37.       SUB_STYLE +
  38.       ";margin-left:-" +
  39.       marginLeft / 2 +
  40.       "px;margin-top:-" +
  41.       marginTop / 2 +
  42.       "px;";
  43.     //创建 header
  44.     var header = document.createElement("div");
  45.     header.className = "dialog_header";
  46.     header.style = dialog_header_style;
  47.     var headerBtn = document.createElement("div");
  48.     headerBtn.style =
  49.       "cursor:pointer;text-align:right;padding-right:10px;font-size: 20px;user-select: none;";
  50.     headerBtn.textContent = "x";
  51.     headerBtn.onclick = function () {
  52.       mainFrameSetParent.removeChild(dialog);
  53.     };
  54.     header.appendChild(headerBtn);
  55.     //创建 iframe 包裹层
  56.     var iframe = document.createElement("iframe");
  57.     iframe.src = pageUrl;
  58.     iframe.className = "modernDialogIframe";
  59.     iframe.style = IFAME_STYLE + iframeStyle;
  60.     iframe.destroy = function (returnValue) {
  61.       resolve(returnValue);
  62.       mainFrameSetParent.removeChild(dialog);
  63.       removeStorageClass();
  64.     };
  65.     dialogBody.appendChild(header);
  66.     dialogBody.appendChild(iframe);
  67.     dialog.appendChild(dialogBody);
  68.     var removeStorageClass = function () {
  69.       var existClass = sessionStorage.getItem("dialogClass");
  70.       if (existClass) {
  71.         sessionStorage.setItem(
  72.           "dialogClass",
  73.           existClass.split(",").pop().join(",")
  74.         );
  75.       }
  76.     };
  77.     //将创建好的弹框插入顶层 document
  78.     mainFrameSetParent.appendChild(dialog);
  79.     // 通过sessionStorage 存储当前显示的弹框的类名,给某些特定页面(通过windbw.close 关闭不了的页面,因为里面的window可能表单操作刷新了window)使用
  80.     var session = sessionStorage.getItem('dialogClass')
  81.     sessionStorage.setItem('dialogClass',session ? (session + ',' + dialog.className) : dialog.className)
  82.        
  83.     var modernDialogIframe = topDoc.querySelector(
  84.       "." + dialog.className + " .modernDialogIframe"
  85.     );
  86.     var tempValue = null;
  87.     //监听 iframe 包裹的目标页面的加载情况
  88.     modernDialogIframe.contentwindow.addEventListener("load", function () {
  89.       this.dialogArguments = comeInParams;
  90.       this.oldClose = this.close;
  91.       //重写当前页面的 window.close
  92.       this.close = function () {
  93.         tempValue = this.returnValue;
  94.         setTimeout(function () {
  95.           resolve(tempValue);
  96.         }, 10);
  97.         mainFrameSetParent.removeChild(dialog);
  98.         removeStorageClass();
  99.         this.oldClose();
  100.       };
  101.     });
  102.   });
  103. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册