javascript - 循环使用 FileReader 仅显示 div 网格中的最后一个图像
问题描述
我正在尝试创建一个 HTML 表单,允许用户上传最多 5 张图片。在用户选择图像(从文件系统中使用<input multiple>
)后,我想将它们显示在 5 个 div 中(ID 从 #contactImage0 到 #contactImage4)。
为了实现这一点,我使用 vanilla JS 循环选择的图像并将它们设置为相应 div 中的背景图像。问题是只有选择中的最后一张图像才会真正显示出来。所有其他 div 保持为空。
在调试了一下之后,我发现除了最后一个图像之外的所有图像都reader.result
返回“”,但我无法弄清楚为什么我传递给的“图像”变量reader.readAsDataURL()
似乎是有效的。
为什么会这样,我该如何解决?
HTML:
<div id="contactImage0" class="imagePreview"></div>
<div id="contactImage1" class="imagePreview"></div>
<div id="contactImage2" class="imagePreview"></div>
<div id="contactImage3" class="imagePreview"></div>
<div id="contactImage4" class="imagePreview"></div>
<input id="upload" type="file" onchange="LoadImage(this)" name="image" accept="image/*" multiple>
JavaScript:
function LoadImage(input){
if (input.files.length > 5){
alert("You may only select a maximum of 5 images!");
// TODO: Remove selected images
return;
}
var i;
for (i = 0; i < input.files.length; i++){
var image = input.files[i]
var imageDiv = 'contactImage' + i.toString();
var element = document.getElementById(imageDiv);
var reader = new FileReader();
reader.onloadend = function(){
element.style.backgroundImage = "url(" + reader.result + ")"; // <-- RETURNS EMPTY STRING (EXCEPT FOR LAST IMAGE)
}
if(image){
reader.readAsDataURL(image);
}else{
}
}
}
CSS (Shouldn't be the cause of the problem but you never know):
.imagePreview{
margin: .5em;
display: inline-block;
width: calc(100% - 1em);
height: 80px;
background-color: #fff;
background-image:url('');
background-size:cover;
background-position: center;
}
解决方案
见https://dzone.com/articles/why-does-javascript-loop-only-use-last-value
解决方案 1 - 创建一个新函数 setElementBackground
for (i = 0; i < input.files.length; i++) {
setElementBackground(input.files[i], i);
}
function setElementBackground(file, i) {
var image = file;
var imageDiv = "contactImage" + i.toString();
var element = document.getElementById(imageDiv);
var reader = new FileReader();
reader.onloadend = function() {
element.style.backgroundImage = "url(" + reader.result + ")";
};
if (image) {
reader.readAsDataURL(image);
}
}
解决方案 2 - 在 for 循环中使用另一个闭包
for (i = 0; i < input.files.length; i++) {
(function() {
var count = i;
var image = input.files[count];
var imageDiv = "contactImage" + count.toString();
var element = document.getElementById(imageDiv);
var reader = new FileReader();
reader.onloadend = function() {
element.style.backgroundImage = "url(" + reader.result + ")";
};
if (image) {
reader.readAsDataURL(image);
}
})();
}
推荐阅读
- mysql - 使用 nodemailer 获取 SQL 数据并发送多封电子邮件?
- ios - React Native 多行垂直居中文本就 IOS 麻烦
- c# - 在 XAML 设计器中找不到 DataContext 类(虽然一切看起来都很好)
- c# - 调整波形文件音量时出现 NAudio 错误
- angular - 语音识别回调 this 未在回调中定义
- powerbi - 循环依赖计算列 Power BI Desktop
- firebase - 如何允许用户从 Firebase 存储下载
- javascript - 复制到行表中的剪贴板 href url
- vb.net - 通过自定义 GUI 控制外部应用程序
- java - 从 NavigableMap 中提取列表