JS设置img标签src属性失败,多文件上传仅最后一张预览正常
问题原因
你的代码遇到了JavaScript中异步回调+var变量作用域的典型问题:
- 你在for循环中使用
var声明cloned变量,var不存在块级作用域,整个函数范围内只有一个cloned变量,每次循环都会覆盖上一次循环给cloned赋的值 - FileReader的
onload属于异步回调,会等待整个for循环执行完毕后才会依次触发。等回调执行时,cloned已经被覆盖为最后一次循环创建的克隆节点,reader也指向最后一次循环生成的FileReader实例,所以所有回调只会给最后一个图片节点赋值src,前面的节点不会被修改。
修复方案
最简单的修复方式是将循环内的变量声明从var替换为具有块级作用域的let,同时用事件参数获取读取结果,避免变量引用异常:
function previewImage(element){ if(element.files.length > 0){ // 循环变量i用let声明,生成块级作用域 for(let i=0;i<element.files.length;i++){ const main=document.getElementById("showPic"); // cloned用let声明,每次循环生成独立的变量实例 let cloned=main.cloneNode(true); const reader = new FileReader(); reader.readAsDataURL(element.files[i]); cloned.id="showPic"+i; // 避免用纯数字作为id,不符合DOM id规范 cloned.children[0].id="imgTag"+i; // 通过事件参数e获取读取结果,消除reader变量引用问题 reader.onload=(e)=>{ cloned.children[0].src=e.target.result; } cloned.style.display="block"; document.getElementById("picsContainer").appendChild(cloned); } } }
优化建议
你也可以使用URL.createObjectURL()实现预览,性能比FileReader更高,不需要将整个文件转成base64格式:
function previewImage(element){ if(element.files.length > 0){ for(let i=0;i<element.files.length;i++){ const main=document.getElementById("showPic"); let cloned=main.cloneNode(true); const currentFile = element.files[i]; cloned.id="showPic"+i; cloned.children[0].id="imgTag"+i; // 直接生成临时预览地址 cloned.children[0].src = URL.createObjectURL(currentFile); cloned.style.display="block"; document.getElementById("picsContainer").appendChild(cloned); // 图片加载完成后释放临时地址,优化内存占用 cloned.children[0].onload = () => { URL.revokeObjectURL(cloned.children[0].src); } } } }
另外你的移除按钮当前调用的removeUpload()没有传参,后续适配多节点时建议传入当前节点的id或者DOM引用,避免无法定位要删除的目标节点。
内容的提问来源于stack exchange,提问作者Bhaumik Bhatt
相关产品推荐
相关产品推荐

