改造jsp項目的alert框和confirm框
背景
之前項目的模態框改造完成,業務也想把頁面中的提示框和確認框也改造一下;這里記錄一下改造中的細節。
之前項目中的提示框和確認框用的是瀏覽器自帶的 alert 和 confirm。改造之前無法支持業務一些復雜一點的需求,遂將之改造;
實現
彈框層級設計參考了 element 和 antd,默認樣式也是復用了他們的樣式。層級從父到子如下所示

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);
}

浙公網安備 33010602011771號