改造jsp项目的alert框和confirm框

背景

之前项目的模态框改造完成,业务也想把页面中的提示框和确认框也改造一下;这里记录一下改造中的细节。

之前项目中的提示框和确认框用的是浏览器自带的 alertconfirm。改造之前无法支持业务一些复杂一点的需求,遂将之改造;

实现

弹框层级设计参考了 elementantd,默认样式也是复用了他们的样式。层级从父到子如下所示

改造jsp项目的alert框和confirm框

messageBoxWrap 是弹出框包裹层和遮罩层。messageBox 是弹出框本身,里面包含了标题,内容,按钮。

而且因为默认 confirm 框会有返回值,所以这里改造后的也就返回了一个 Promise,并且只会 resolve(true) 或者 resolve(false)

// type 区分是 alert 还是 confirm // paramSting 表示提示框的内容,项目中没有自定义标题的需求,所以这里提示框都用统一的标题 function showMessagebox(type, paramString) {   //获取项目顶层的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) => {       // 具体实现   }); } 

注意事项

有几个注意的点是

  • 创建弹框时需要禁用键盘事件,弹框消失后启用键盘事件,防止弹框还未消失,使用 tab+enter去了其他页面的情况
  • 需要避免有一个弹框存在的情况下,重复点击创建弹框

然后是具体实现。

添加默认样式

/*弹框的默认样式;*/ var messageBoxWrap_class = "modernMessagebox"; var messageBoxWrap_style =   "width:100%;height:100%;position:fixed;top:0;left:0;text-align:center;"; var messageBox_style =   "user-select:none;display: inline-block;width: 420px;padding: 10px 0px 20px;vertical-align: middle;background-color: #fff;border-radius: 4px;border: 1px solid #ebeef5;font-size:18px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);text-align: left;"; var header_style =   "padding: 10px 16px 10px;font-size:14px;display:flex;justify-content: space-between;"; var content_style = "padding: 10px 15px;color: #606266;font-size: 14px;"; var footer_style = "padding: 5px 15px 0;text-align: right;"; var button_style =   "display: inline-block;line-height: 1;wite-space: nowrap;cursor: pointer;background: #fff;border: 1px solid #dcdfe6;color: #606266;-webkit-appearance: none;text-align:center;box-sizing:border-box;outline:0;margin:0;transition:.1s;font-weight:500;padding:10px 16px;font-size:12px;border-radius:3px;"; var button_primary =   "color: #fff;background: rgb(11, 87, 208);border: 1px solid rgb(11, 87, 208);border-radius: 20px 20px;";  

创建 messageBoxWrap,添加遮罩层

var messageBoxWrap = document.createElement("div"); messageBoxWrap.setAttribute("tabindex", "-1"); // 设置使其不能通过tab键聚焦 messageBoxWrap.className = messageBoxWrap_class + Date.now(); // 每次弹框的类名都是唯一的  // 使 messageBoxWrap 覆盖在顶层 window 上 messageBoxWrap.style = messageBoxWrap_style + ";width:" + topDocBody.clientWidth + "px;"; 

创建 messageBox,添加 header,content,footer

1、创建messageBox

var messageBox = document.createElement("div"); messageBox.className = "messageBox"; messageBox.style = messageBox_style; 

2、创建 header

//创建 header var header = document.createElement("div"); header.className = "messageBox_header"; header.style = header_style; var headerText = document.createElement("div"); headerText.textContent = "提示"; var headerBtn = document.createElement("div"); headerBtn.style = "cursor:pointer;text-align:right;"; headerBtn.textContent = "x"; headerBtn.onclick = function () {   mainFrameSetParent.removeChild(messageBoxWrap);   enableKeyboard(); }; 

当点击头部的关闭按钮时,在顶层文档对象(mainFrameSetParent)中移除弹框。这里 enableKeyboard
表示移除弹框后恢复键盘事件。因为有时候业务操作飞快,有时候因为电脑卡,弹框还没完全关闭,使用键盘操作去到了其他页面,导致弹框显示在了其他页面。

3、创建 content 包裹层

//创建 content 包裹层 var contentBox = document.createElement("div"); contentBox.className = "messageBox_content"; contentBox.style = content_style; contentBox.textContent = paramString; 

4、创建 footer

这里如果使 confirm 框,则多一个取消按钮

//创建 footer var footer = document.createElement("div"); footer.className = "messageBox_footer"; footer.style = footer_style; var yesBtn = document.createElement("button"); yesBtn.style = button_style + button_primary; yesBtn.textContent = type === "confirm" ? "确认" : "确定"; yesBtn.onclick = function () {   if (type === "alert") {     if (currentAlertBoxCount > 0) {       currentAlertBoxCount--;     }   }   resolve(true);   mainFrameSetParent.removeChild(messageBoxWrap);   enableKeyboard(); // 关闭弹框后恢复键盘事件 }; if (type === "confirm") {   var noBtn = document.createElement("button");   noBtn.style =     button_style + "margin-left: 10px;border-radius: 20px 20px;";   noBtn.textContent = "取消";   noBtn.onclick = function () {     resolve(false);     mainFrameSetParent.removeChild(messageBoxWrap);     enableKeyboard(); // 关闭弹框后恢复键盘事件   }; } footer.appendChild(yesBtn); if (type === "confirm") {   footer.appendChild(noBtn); } 

5、将创建的弹框插入顶层文档

创建弹框时,使焦点聚焦到弹框,并且禁用键盘事件。

messageBox.appendChild(header); messageBox.appendChild(contentBox); messageBox.appendChild(footer); messageBoxWrap.appendChild(messageBox); //将创建好的弹框插入顶层 document mainFrameSetParent.appendChild(messageBoxWrap); messageBoxWrap.focus(); disableKeyboard(); 

6、页面调用弹出框

设置 currentAlertBoxCount 代表 alert 框的数量,避免同时出现多个弹框

var currentAlertBoxCount = 0; async function modernConfirm(str) {   return await showMessagebox("confirm", str); } async function modernAlert(str) {   if(currentAlertBoxCount>0){     return   }   currentAlertBoxCount++;   return await showMessagebox("alert", str); } 

完整代码

/*弹框的默认样式;*/ var messageBoxWrap_class = "modernMessagebox"; var messageBoxWrap_style =   "width:100%;height:100%;position:fixed;top:0;left:0;text-align:center;"; var messageBox_style =   "user-select:none;display: inline-block;width: 420px;padding: 10px 0px 20px;vertical-align: middle;background-color: #fff;border-radius: 4px;border: 1px solid #ebeef5;font-size:18px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);text-align: left;"; var header_style =   "padding: 10px 16px 10px;font-size:14px;display:flex;justify-content: space-between;"; var content_style = "padding: 10px 15px;color: #606266;font-size: 14px;"; var footer_style = "padding: 5px 15px 0;text-align: right;"; var button_style =   "display: inline-block;line-height: 1;wite-space: nowrap;cursor: pointer;background: #fff;border: 1px solid #dcdfe6;color: #606266;-webkit-appearance: none;text-align:center;box-sizing:border-box;outline:0;margin:0;transition:.1s;font-weight:500;padding:10px 16px;font-size:12px;border-radius:3px;"; var button_primary =   "color: #fff;background: rgb(11, 87, 208);border: 1px solid rgb(11, 87, 208);border-radius: 20px 20px;"; var currentAlertBoxCount = 0; //弹框时禁用键盘事件,弹框消失后启用键盘事件,防止弹框还未消失,使用 tab+enter去了其他页面的情况 let keyboardDisabled = false; function disableKeyboard() {   keyboardDisabled = true;   document.addEventListener("keydown", handleKeyDown); } function enableKeyboard() {   keyboardDisabled = false;   document.removeEventListener("keydown", handleKeyDown); } function handleKeyDown(event) {   if (keyboardDisabled) {     event.preventDefau1t();   } } // type 区分是 alert 还是 confirm // paramSting 表示提示框的内容,项目中没有自定义标题的需求,所以这里提示框都用统一的标题 function showMessagebox(type, paramString) {   //获取项目顶层的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 messageBoxWrap = document.createElement("div");     messageBoxWrap.setAttribute("tabindex", "-1");     messageBoxWrap.className = messageBoxWrap_class + Date.now();     messageBoxWrap.style = messageBoxWrap_style + ";width:" + topDocBody.clientWidth + "px;";     var messageBox = document.createElement("div");     messageBox.className = "messageBox";     messageBox.style = messageBox_style;     //创建 header     var header = document.createElement("div");     header.className = "messageBox_header";     header.style = header_style;     var headerText = document.createElement("div");     headerText.textContent = "提示";     var headerBtn = document.createElement("div");     headerBtn.style = "cursor:pointer;text-align:right;";     headerBtn.textContent = "x";     headerBtn.onclick = function () {       mainFrameSetParent.removeChild(messageBoxWrap);       enableKeyboard();     };     header.appendChild(headerText);     header.appendChild(headerBtn);     //创建 content 包裹层     var contentBox = document.createElement("div");     contentBox.className = "messageBox_content";     contentBox.style = content_style;     contentBox.textContent = paramString;     //创建 footer     var footer = document.createElement("div");     footer.className = "messageBox_footer";     footer.style = footer_style;     var yesBtn = document.createElement("button");     yesBtn.style = button_style + button_primary;     yesBtn.textContent = type === "confirm" ? "确认" : "确定";     yesBtn.onclick = function () {       if (type === "alert") {         if (currentAlertBoxCount > 0) {           currentAlertBoxCount--;         }       }       resolve(true);       mainFrameSetParent.removeChild(messageBoxWrap);       enableKeyboard();     };     if (type === "confirm") {       var noBtn = document.createElement("button");       noBtn.style =         button_style + "margin-left: 10px;border-radius: 20px 20px;";       noBtn.textContent = "取消";       noBtn.onclick = function () {         resolve(false);         mainFrameSetParent.removeChild(messageBoxWrap);         enableKeyboard();       };     }     footer.appendChild(yesBtn);     if (type === "confirm") {       footer.appendChild(noBtn);     }      messageBox.appendChild(header);     messageBox.appendChild(contentBox);     messageBox.appendChild(footer);     messageBoxWrap.appendChild(messageBox);     //将创建好的弹框插入顶层 document     mainFrameSetParent.appendChild(messageBoxWrap);     messageBoxWrap.focus();     disableKeyboard();   }); } async function modernConfirm(str) {   return await showMessagebox("confirm", str); } async function modernAlert(str) {   if(currentAlertBoxCount>0){     return   }   currentAlertBoxCount++;   return await showMessagebox("alert", str); } 

发表评论

评论已关闭。

相关文章