show.bs.modal 在 modal.show() 调用后立即触发,此时 modal 尚未渲染进 dom、不可见、offsetheight === 0;shown.bs.modal 在 css 过渡完全结束后触发,modal 已完全可见、display === 'block',适合聚焦、读取尺寸或初始化组件。

show.bs.modal 和 shown.bs.modal 的区别在哪
这两个事件都发生在 Modal 显示过程中,但触发时机和 DOM 状态完全不同,选错会导致操作失败或 UI 闪动。
-
show.bs.modal在modal.show()被调用后**立即触发**,此时 Modal 还没渲染进 DOM,offsetHeight === 0,.modal-dialog元素不可见,不能做 DOM 查找或样式修改 -
shown.bs.modal在 CSS 过渡动画**完全结束**后触发,此时 Modal 已完全可见,getComputedStyle(modal).display === 'block',适合读取尺寸、聚焦输入框、初始化第三方组件(如 CodeMirror) - 常见误用:在
show.bs.modal里调用$(this).find('input').focus(),结果找不到元素或焦点失效;应挪到shown.bs.modal - 调试建议:在两个回调里都打印
console.log('height:', this.offsetHeight),对比数值变化
如何在 show.bs.modal 中安全传入动态数据
Modal 本身不支持参数传递,所有上下文数据必须靠 show.bs.modal 事件 + event.relatedTarget 获取,这是唯一稳定入口。
- 触发按钮必须带
data-*属性,例如:<button data-user-id="123" data-action="edit" data-bs-toggle="modal" data-bs-target="#myModal">编辑</button> - 监听时直接读
event.relatedTarget.dataset.userId(注意驼峰转短横线,userId→user-id),不要用 jQuery 的.data(),它会自动类型转换 - 填充内容前先清空残留:
modalEl.querySelector('.modal-body').innerHTML = '',否则上一次的数据可能还在 - 如果 Modal 是动态插入的(如 innerHTML 拼接),确保事件绑定在 DOM 插入之后,且只绑一次;重复绑定会导致多次执行
Bootstrap 5+ 必须绑定到 DOM 元素,不是 Modal 实例
Bootstrap 5 移除了 jQuery 依赖,bootstrap.Modal 实例对象不是 EventTarget,不能直接 addEventListener —— 这是升级后最常报错的地方。
- ❌ 错误写法:
const modal = new bootstrap.Modal(el); modal.addEventListener('show.bs.modal', handler)→ 报错addEventListener is not a function - ✅ 正确写法:事件绑定到原始 DOM 元素,
el.addEventListener('show.bs.modal', handler),其中el是document.getElementById('myModal') - 实例(
modal.show()/modal.hide())只用于手动控制显隐,不参与事件流 - 如果 Modal 是 JS 动态生成并插入的,务必等
el存在于 document 后再绑定事件,比如放在el.insertAdjacentHTML()之后,或用document.addEventListener('DOMContentLoaded', ...)
React/Vue 项目里监听失效的根本原因
不是事件名写错,而是框架卸载组件时没清理 jQuery 或原生事件监听器,导致回调引用失效、重复绑定或执行在已销毁的组件上。
- Vue 场景:在
mounted里绑定el.addEventListener('shown.bs.modal', ...),但没在beforeUnmount解绑 → 下次打开可能执行两次,或this指向 null - React 场景:在
useEffect里绑定,但 cleanup 函数没调用el.removeEventListener→ 内存泄漏 + 回调中访问已 unmount 的 state 报错 - 更稳妥方案:放弃混用,改用
react-bootstrap或@headlessui/react等纯框架方案;若必须用 Bootstrap 5 原生 JS,则严格配对绑定/解绑,并避免在回调里直接读写组件 state - 额外坑点:Modal 内部表单元素在
hidden.bs.modal触发时可能已被移除,读值必须在shown.bs.modal或hidden.bs.modal的同步回调里立刻完成,别 setTimeout











