我正面临这个问题我总是得到我的图像数组中的最后一个图像,因为Filereader库函数onloadend的种类。 如何为我的文件夹中的所有图像获取base64。
<input id="file-input" multiple webkitdirectory type="file" />
var input = document.getElementById('file-input');
var file_names = "";
var entries_length = 0;
var entries_count = 0;
var image = new Array();
var obj = {};
var j = 0;
input.onchange = function(e) {
var files = e.target.files; // FileList
entries_length = files.length;
console.log(files);
for (var i = 0, f; f = files[i]; ++i){
console.log("i:"+i);
entries_count = entries_count + 1;
//console.debug(files[i].webkitRelativePath);
if(files[i].type=="image/jpeg")
{
var string = files[i].webkitRelativePath;
var name = string.split("/")[3]; //this is because my image in 3rd dir in the folder
var reader = new FileReader();
reader.onloadend = function() {
obj.name = string.split("/")[3];
obj.image = reader.result;
image[j] = obj;
j = j+1;
}
reader.readAsDataURL(files[i]);
}
}
console.log(image);
}
答案 0 :(得分:0)
问题是由异步加载文件引起的。您遍历数组并每次为阅读器设置onloadend
处理程序,然后通过调用readAsDataURL
开始加载。
一个问题是,当第一个图像加载时,for
循环可能已完成,i
已经在数组的最后一个索引处。
此时,从files[i].webkitRelativePath
获取路径将为您提供最后的文件名,而不是您期望的文件名。
检查example for readAsDataURL on MDN以查看一个可能的解决方案 - 每个加载都在一个单独的函数中执行,该函数保留其范围以及file.name
。不要因他们正在使用的结构而被推迟:[].forEach.call(files, readAndPreview)
。这是一种映射文件的方法,这些文件是FileList而不是常规数组(因此列表没有自己的forEach方法)。
因此,将加载逻辑包装在一个以文件对象作为参数的函数中就足够了:
var images = [];
function loadFile(f) {
var reader = new FileReader();
reader.onloadend = function () {
images.push({
name : f.name, // use whatever naming magic you prefer here
image : reader.result
});
};
reader.readAsDataURL(f);
}
for (var i=0; i<files.length; i++) {
loadFile(files[i]);
}
函数的每次调用都“记住”调用它的文件对象,并防止文件名混乱。如果您有兴趣,read up on closures。
这也有隔离读者对象的良好效果,因为我有一种潜在的怀疑,虽然你每次迭代创建一个新的“本地”读者,javascript范围规则很奇怪,读者也可能互相干扰(如果一个阅读器正在加载会发生什么,但是在相同的范围内你创建一个具有相同变量名称的新阅读器?不确定。)
现在,您不知道加载所有图像需要多长时间,因此如果您想在此之后立即执行操作,则每次调用onloadend
时都必须执行检查。这是异步行为的本质。
顺便说一句,我应该注意,手动跟踪images
的最后一个索引({1}}是没有意义的。你应该使用j
。手动保存索引可以提供错误的可能性。