我想在文件夹中加载图像,并希望在我的 js 中获取 base64 中的所有图像以供将来使用

I want to load images withen the folder and want to get all images in base64 in my js for future use

我面临的问题是,由于某种 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);
    }        

问题是由文件的异步加载引起的。您遍历数组并每次为 reader 设置 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]);
}

函数的每次调用 'remembers' 调用它的文件对象,并防止文件名弄乱。如果您有兴趣,read up on closures.

这也有很好的隔离你的 reader 对象的效果,因为我有一个潜在的怀疑,虽然你创建了一个新的 'local' reader 每次迭代,javascript 范围规则很奇怪 readers 也可能相互干扰(如果一个 reader 正在加载会发生什么,但是在相同的范围内你创建一个新的 reader 具有相同的变量名?不确定)。

现在,你不知道加载所有图像需要多长时间,所以如果你想在那之后立即采取行动,你必须在每次 onloadend 时执行检查被调用。这就是异步行为的本质。

顺便说一句,我应该注意到手动跟踪 images 的最后一个索引是没有意义的,即 j。你应该只使用 images.push({ name: "bla", image: "base64..." })。手动保留索引会带来错误的可能性。