You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:51:12