选中图片后需用filereader读取并转data url显示预览,须校验文件类型、处理ios兼容性、避免覆盖预览图、优化缩放渲染,并添加onerror兜底。

input type="file" 选中图片后如何读取并显示预览
浏览器原生不自动显示上传文件内容,必须用 FileReader 手动读取 input.files[0] 并转成 Data URL。关键不是绑定 change 事件,而是确保只处理图片类型,避免用户选中 PDF 或视频时 readAsDataURL 成功但后续 img.src 无法渲染。
实操建议:
- 检查
input.files.length > 0和input.files[0].type.startsWith('image/'),否则跳过 - 创建
new FileReader()实例,监听load事件,在回调里把e.target.result赋给img.src - 别在
error事件里静默吞错——FileReader报错时e.target.error有具体原因,比如NOT_READABLE_ERR(文件被占用)
多图上传时如何避免 img 标签被反复覆盖
如果页面只有一个 <img id="preview">,但用户连续选了 3 次不同图片,最终只显示最后一次。这不是 bug,是预期行为;但多数场景需要保留历史或支持多图轮播,就得改结构。
实操建议:
- 每次选中新图,用
document.createElement('img')新建节点,追加到容器(如<div id="preview-container">),而不是复用旧 <code><img> - 限制数量:在添加前检查
previewContainer.children.length,超限时先.removeChild(previewContainer.firstElementChild) - 记得给新
img设置width和max-width: 100%,否则大图会撑破布局 - 不要用
visibility: hidden或opacity: 0隐藏 input,改用position: absolute; left: -9999px - 确保
input是可聚焦的(没加disabled或readonly),否则 iOS 会拒绝访问文件系统 - 测试时用真实设备——模拟器常绕过这些限制,导致上线后才发现白屏
- 给预览
img加image-rendering: -webkit-optimize-contrast(Safari)和image-rendering: crisp-edges(Chrome/Firefox),强制启用 nearest-neighbor 插值 - 服务端缩略图才是终极解法——前端预览只用于快速反馈,高质展示交给后端生成 800px 宽的缩略图再返回 URL
- 如果必须前端压缩,别用 canvas drawImage 简单缩放,要用
createImageBitmap()+resizeAPI(注意兼容性,Firefox 72+ / Chrome 84+)
移动端 iOS Safari 选图后预览空白的常见原因
iOS 15+ 的 Safari 对 FileReader 读取本地文件更严格,尤其当 input 被包裹在 label 里、或用了 display: none 隐藏原始 input 时,容易触发安全拦截,FileReader 的 load 事件根本不触发。
实操建议:
预览图缩放失真或模糊怎么办
直接把 Data URL 赋给 img.src 后,浏览器按原始尺寸渲染,若图片分辨率远高于容器,会被 CSS 缩放导致像素糊。这不是 JS 问题,是 CSS 渲染策略。
实操建议:
真正难的不是读取文件,而是处理用户乱点、网络延迟、iOS 权限弹窗失败、缩略图尺寸抖动这些边界情况。留个 img.onerror 处理加载失败,比写十行预览逻辑都管用。











