js模拟Prompt 对话框
效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义 Prompt 对话框</title>
<style>
</style>
</head>
<body>
<script>
// 样式变量
const dialogStyleText = `
.prompt-dialog {
display: none;
position: fixed;
z-index: 9999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
border: 1px solid #ccc;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
width: 400px; /* 设置初始宽度 */
text-align: left; /* 左对齐 */
font-size: 14px;
}
.prompt-overlay {
display: none;
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0);
/*background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(3px);*/
}
.prompt-dialog .prompt-text {
margin-bottom: 10px;
}
.prompt-dialog .prompt-input-container {
margin-bottom: 20px;
}
.prompt-dialog .prompt-input-container input[type="text"] {
width: calc(100% - 16px); /* 输入框占满容器宽度 */
padding: 5px; /* 增加填充 */
margin-bottom: 10px;
}
.prompt-dialog .prompt-input-container input[type="text"]:last-child {
margin-bottom: 0;
}
.prompt-dialog .prompt-button-container {
display: flex;
justify-content: flex-end; /* 按钮靠右 */
}
.prompt-dialog button {
margin-left: 10px;
}
@keyframes prompt-shake {
0% { transform: translate(-50%, -50%) rotate(0deg); }
25% { transform: translate(-50%, -50%) rotate(2deg); }
50% { transform: translate(-50%, -50%) rotate(0deg); }
75% { transform: translate(-50%, -50%) rotate(-2deg); }
100% { transform: translate(-50%, -50%) rotate(0deg); }
}
.prompt-dialog.prompt-shake {
animation: prompt-shake 0.5s ease-in-out;
}
`;
// HTML模板
const dialogHtml = `
<div class="prompt-text" id="promptText">请输入</div>
<div class="prompt-input-container">
<input type="text" id="promptInput" />
</div>
<div class="prompt-button-container">
<button id="promptCancel">取消</button>
<button id="promptSubmit">确认</button>
</div>
`;
// 创建样式
const dialogStyle = document.createElement('style');
dialogStyle.textContent = dialogStyleText;
document.head.appendChild(dialogStyle);
// 创建对话框
const dialog = document.createElement('div');
dialog.className = 'prompt-dialog';
dialog.id = 'promptDialog';
dialog.innerHTML = dialogHtml;
document.body.appendChild(dialog);
// 创建遮罩层
const overlay = document.createElement('div');
overlay.className = 'prompt-overlay';
document.body.appendChild(overlay);
// 获取元素
const promptContainer = document.querySelector(".prompt-input-container");
const submitButton = document.getElementById('promptSubmit');
const cancelButton = document.getElementById('promptCancel');
const promptText = document.getElementById('promptText');
let focusEl;
// 弹出对话框
function showPrompt(message = '', defaultValue = '', okName="确定", cancelName="取消", width=400, modalMode=true, clickOverlayClose=false) {
return new Promise((resolve, reject) => {
// 初始化窗口
promptText.textContent = message;
let input = document.getElementById('promptInput');
if(!input) {
promptContainer.innerHTML = `<input type="text" id="promptInput" />`;
input = document.getElementById('promptInput');
}
input.value = defaultValue || '';
submitButton.textContent = okName || '确定';
cancelButton.textContent = cancelName || '取消';
if(!cancelName) cancelButton.style.display = 'none';
dialog.style.display = 'block';
if(modalMode) overlay.style.display = 'block';
input.focus();
focusEl = promptContainer.querySelector(":focus");
// 监听按钮点击事件
submitButton.addEventListener('click', () => {
dialog.style.display = 'none';
if(modalMode) overlay.style.display = 'none';
document.removeEventListener('keydown', handleKeydown);
resolve(input.value);
});
cancelButton.addEventListener('click', () => {
dialog.style.display = 'none';
if(modalMode) overlay.style.display = 'none';
document.removeEventListener('keydown', handleKeydown);
resolve(null);
});
// 添加键盘事件监听器
const handleKeydown = () => {
if (event.key === 'Escape') {
cancelButton.click();
} else if (event.key === 'Enter') {
submitButton.click();
}
};
document.addEventListener('keydown', handleKeydown);
// 监听焦点事件,focus冒泡必须第三参数是true
promptContainer.addEventListener('focus', (event) => {
focusEl = event.target;
}, true);
// 添加点击遮罩层关闭对话框的功能
if(modalMode){
overlay.addEventListener('click', () => {
// 点击遮罩层关闭弹窗
if(clickOverlayClose) cancelButton.click();
// 重新获取焦点
if(focusEl) focusEl.focus();
// 添加抖动类
dialog.classList.add('prompt-shake');
// 移除抖动类
setTimeout(() => {
dialog.classList.remove('prompt-shake');
}, 500);
});
}
});
}
// 弹出对话框表单
function showPromptForm(message = '', html = '', onSubmit = null, onOpen = null, okName="确定", cancelName="取消", width=400, modalMode=true, clickOverlayClose=false) {
return new Promise((resolve, reject) => {
// 初始化窗口
if(html) promptContainer.innerHTML = html;
promptText.textContent = message;
submitButton.textContent = okName || '确定';
cancelButton.textContent = cancelName || '取消';
if(!cancelName) cancelButton.style.display = 'none';
dialog.style.display = 'block';
if(modalMode) overlay.style.display = 'block';
if(typeof onOpen === 'function') onOpen(promptContainer);
focusEl = promptContainer.querySelector(":focus");
// 监听按钮点击事件
submitButton.addEventListener('click', () => {
dialog.style.display = 'none';
if(modalMode) overlay.style.display = 'none';
document.removeEventListener('keydown', handleKeydown);
if(typeof onSubmit === 'function') {
resolve(onSubmit(promptContainer));
} else {
resolve(undefined);
}
});
cancelButton.addEventListener('click', () => {
dialog.style.display = 'none';
if(modalMode) overlay.style.display = 'none';
document.removeEventListener('keydown', handleKeydown);
resolve(null);
});
// 添加键盘事件监听器
const handleKeydown = () => {
if (event.key === 'Escape') {
cancelButton.click();
} else if (event.key === 'Enter') {
submitButton.click();
}
};
document.addEventListener('keydown', handleKeydown);
// 监听焦点事件,focus冒泡必须第三参数是true
promptContainer.addEventListener('focus', (event) => {
focusEl = event.target;
}, true);
// 添加点击遮罩层关闭对话框的功能
if(modalMode){
overlay.addEventListener('click', () => {
// 点击遮罩层关闭弹窗
if(clickOverlayClose) cancelButton.click();
// 重新获取焦点
if(focusEl) focusEl.focus();
// 添加抖动类
dialog.classList.add('prompt-shake');
// 移除抖动类
setTimeout(() => {
dialog.classList.remove('prompt-shake');
}, 500);
});
}
});
}
// 示例用法
(async () => {
// showPrompt 示例用法
const result = await showPrompt('这里是提示文本', '');
console.log(result);
// showPromptForm 示例用法
// const result = await showPromptForm('这里是提示文本', `
// <input type="text" id="promptName" placeholder="标题" />
// <input type="text" id="promptHref" placeholder="链接" />
// `, (promptContainer) => {
// const inputs = promptContainer.querySelectorAll('input[type="text"]');
// const values = Array.from(inputs).map(input => input.value);
// return values;
// }, ()=> {
// document.getElementById("promptName").focus();
// });
// console.log(result);
})();
</script>
</body>
</html>
注意事项
-
showPrompt
和showPromptForm
的区别,见上面的效果图,上面一个是 showPrompt,这个是对 window.prompt 的模拟,下面一个是 showPromptForm,是对 showPrompt 的扩展,可以用于实现复杂的表单功能。 - 默认使用模态模式,如果不使用模态(即不使用遮罩层),调用时把 modalMode 参数设置为 false 即可。
- 模态窗口的背景色默认透明,和window.prompt保持一致,如果你想修改背景色,可以修改样式.prompt-overlay 的
background-color: rgba(0, 0, 0, 0);
这行代码。 - 模态窗口的宽度默认是 400px,如果想自定义宽度可通过 width 参数设置。
- 如果想支持
点击遮罩层关闭对话框的功能
,把 clickOverlayClose 参数设置为 true 即可。 - 点确认按钮返回值是字符串,点取消返回值是 null,但 showPromptForm,点确定的返回值是自己定义的。
- 按钮文字可通过
cancelName
和okName
参数设置。 - 更多功能请参考源码。
接口定义及说明如下
// 弹出prompt对话框
// 参数说明
// message 提示消息,类似标题
// defaultValue 输入框默认值
// okName 确认按钮名字
// cancelName 取消按钮名字
// width对话框宽度,默认400,高度根据内容自适应
// modalMode,是否模态窗口,模态窗口,除了当前对话框,其他地方无法点击,false非模态窗,true模态窗
// clickOverlayClose 是否点击遮罩层关闭对话框,仅在模态窗口下有效
function showPrompt(message = '', defaultValue = '', okName="确定", cancelName="取消", width=400, modalMode=true, clickOverlayClose=false);
// 弹出自定义prompt对话框(可自定义定义复杂表单)
// 参数说明
// message 提示消息,类似标题
// html 对话框自定义表单内容的HTML代码
// onSubmit 提交时的回调函数,对话框的返回值依赖于这个回调函数的返回值
// onOpen 打开窗口时的回调函数,可以在打开窗口话进行一些初始化操作,比如某个输入框设为焦点
// okName 确认按钮名字
// cancelName 取消按钮名字
// width 对话框宽度,默认400px,高度根据内容自适应
// modalMode,是否模态窗口,模态窗口,除了当前对话框,其他地方无法点击,false非模态窗,true模态窗
// clickOverlayClose 是否点击遮罩层关闭对话框,仅在模态窗口下有效
function showPromptForm(message = '', html = '', onSubmit = null, onOpen = null, okName="确定", cancelName="取消", width=400, modalMode=true, clickOverlayClose=false);
思源版prompt
https://ld246.com/article/1723719060687
