onerror事件不冒泡,无法通过事件委托监听img加载失败;必须为每个img单独绑定,推荐内联写法或JS显式赋值,并立即置空onerror防止循环。

onerror 事件本身不冒泡,这是它和 click、input 等事件最根本的区别之一。这意味着你不能像处理点击事件那样,在父容器或 document 上用事件委托统一监听所有 img 的加载失败 —— 绑了也收不到。
为什么不能靠事件委托?
浏览器规范明确规定:img 的 onerror 不支持冒泡,也不支持捕获阶段的自动传播(即使你用 addEventListener 并传 true,也只对能冒泡的事件有效)。它属于“一次性、仅目标触发”的低层级资源错误事件。所以:
- document.addEventListener('error', handler) 捕获不到 img 加载失败
- 给 div 或 table 添加 onclick 可以委托子 img 的点击,但加 onerror 监听器完全无效
- 动态插入的 img,如果没在创建时就绑定 onerror,后续再补也大概率错过时机
可靠绑定的两种落地方式
必须让每个 img 实例自己“扛住”错误,而不是指望上级兜底:
-
内联写法(适合模板可控、非大量动态渲染):

-
JS 显式赋值(适合 Vue/React 组件、或 JS 动态创建 img):
const img = new Image();<br>img.src = url;<br>img.onerror = function() {<br> this.src = '/img/fallback.png';<br> this.onerror = null;<br>};
防重与防循环是刚需
onerror 触发后若再次设置一个可能失败的 src,且未切断事件链,就会无限重试、界面卡顿甚至堆栈溢出:
- 务必在替换 src 后立即执行 this.onerror = null,彻底卸载处理器
- 避免在 onerror 回调里再次赋值为同一 fallback 路径(尤其当 fallback 图本身部署异常时)
- 更稳妥的做法:fallback 图用 base64 内联小图标,或确保其路径绝对稳定(如 CDN 上的 /static/icon-broken.svg)
替代思路:伪元素兜底(无 JS 依赖)
如果项目限制 JS 执行或需服务端直出容错,可用 CSS 伪元素模拟默认图:
- 给 img 设置固定宽高 + object-fit: cover
- 外层容器 relative 定位,用 ::before 画一个灰色占位背景 + 文字提示
- 图片加载成功时,opacity: 1;失败时靠 JS 添加 class 切换显示逻辑,或纯 CSS 配合 :not([src]) 试探(局限较大)
- 优点:不依赖 onerror,无循环风险;缺点:无法自动感知加载失败,需配合 JS 标记状态










