使用 FileReader 循环 <input multiple> 仅显示 div 网格中的最后一张图像
Looping over <input multiple> with FileReader only displays last image in grid of divs
我正在尝试创建一个 HTML 表单,允许用户上传最多 5 张图片。用户选择图像后(使用 <input multiple>
从文件系统),我想在 5 div 秒内显示它们(ID 从 #contactImage0 到 #contactImage4)。
为了实现这一点,我使用 vanilla JS 遍历选定的图像,并将它们设置为相应 div 中的背景图像。问题是只有选区中的最后一张图像才真正显示出来。所有其他 div 保持空白。
调试了一下后我发现除了最后一张图片 reader.result
returns "" 但我不知道为什么我传递给 "image" 变量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);
}
})();
}
我正在尝试创建一个 HTML 表单,允许用户上传最多 5 张图片。用户选择图像后(使用 <input multiple>
从文件系统),我想在 5 div 秒内显示它们(ID 从 #contactImage0 到 #contactImage4)。
为了实现这一点,我使用 vanilla JS 遍历选定的图像,并将它们设置为相应 div 中的背景图像。问题是只有选区中的最后一张图像才真正显示出来。所有其他 div 保持空白。
调试了一下后我发现除了最后一张图片 reader.result
returns "" 但我不知道为什么我传递给 "image" 变量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);
}
})();
}