JavaScript实现可返回用户输入的自定义prompt功能
自定义Prompt弹窗实现方案
你现有代码存在几个致命问题,完全无法跑通预期逻辑:
- 动态创建的弹窗节点没有插入DOM树,页面上根本不会显示弹窗
- 键盘事件回调里的
return只在事件函数内部生效,没法把输入值传回外层ask的调用方 - 缺少遮罩、操作按钮、DOM销毁逻辑,用的时候会出现节点残留、内存泄漏
- 基于DOM实现的自定义弹窗做不到原生
prompt的同步阻塞效果,用Promise封装后配合async/await调用,使用体验和原生方法几乎没有区别,是目前通用的实现方案。
可直接复用的完整实现
function ask(title = '请输入内容') { return new Promise((resolve) => { // 创建遮罩层 const mask = document.createElement('div') Object.assign(mask.style, { position: 'fixed', top: 0, left: 0, width: '100vw', height: '100vh', background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999 }) // 创建弹窗容器 const dialog = document.createElement('div') Object.assign(dialog.style, { width: '400px', padding: '20px', background: '#fff', borderRadius: '8px', boxShadow: '0 2px 12px rgba(0,0,0,0.15)' }) // 填充提示文本 dialog.innerHTML = `<p style="margin:0 0 12px 0;font-size:16px;">${title}</p>` // 创建输入框 const input = document.createElement('input') input.type = 'text' Object.assign(input.style, { width: '100%', padding: '8px 12px', border: '1px solid #dcdfe6', borderRadius: '4px', fontSize: '14px', boxSizing: 'border-box', marginBottom: '20px' }) // 创建按钮组 const btnGroup = document.createElement('div') Object.assign(btnGroup.style, { display: 'flex', justifyContent: 'flex-end', gap: '12px' }) // 取消按钮 const cancelBtn = document.createElement('button') cancelBtn.textContent = '取消' Object.assign(cancelBtn.style, { padding: '6px 16px', border: '1px solid #dcdfe6', background: '#fff', borderRadius: '4px', cursor: 'pointer' }) // 确认按钮 const confirmBtn = document.createElement('button') confirmBtn.textContent = '确认' Object.assign(confirmBtn.style, { padding: '6px 16px', border: 'none', background: '#409eff', color: '#fff', borderRadius: '4px', cursor: 'pointer' }) // 组装节点插入页面 btnGroup.append(cancelBtn, confirmBtn) dialog.append(input, btnGroup) mask.append(dialog) document.body.append(mask) // 弹窗插入后默认聚焦输入框 input.focus() // 统一关闭弹窗方法 const close = (value) => { mask.remove() resolve(value) } // 绑定交互事件 // 回车直接提交输入值 input.addEventListener('keydown', (e) => { if (e.key === 'Enter') close(input.value.trim()) }) // 点击取消返回null cancelBtn.addEventListener('click', () => close(null)) // 点击确认返回输入内容 confirmBtn.addEventListener('click', () => close(input.value.trim())) // 点击遮罩层关闭弹窗,返回null mask.addEventListener('click', (e) => { if (e.target === mask) close(null) }) }) }
调用方式
配合async/await就可以像调用原生prompt一样拿到用户输入结果:
async function runDemo() { const userInput = await ask('请输入你的昵称') if (userInput !== null) { console.log('用户提交的输入:', userInput) } else { console.log('用户取消了输入') } } runDemo()
不要尝试写死循环阻塞线程实现同步调用效果,会直接导致页面整个卡死,Promise+async/await是自定义弹窗的行业标准实现,不会阻塞页面渲染,交互体验和原生弹窗一致。
内容的提问来源于stack exchange,提问作者VirusterDev
相关产品推荐
相关产品推荐

