以编程方式更改输入类型文件的值?

Programmatically changing value of input type file?

我正在尝试生成一些代码,我可以在整个站点中重复使用这些代码,本质上,这些代码是经过一些验证的照片 picker/chooser。这是我的代码:

class PhotoPicker
{
    constructor(element)
    {
        this.element = element;

        //Creating needed HTML Markup
        this.createMarkUp();

        //FileList of valid data.
        this.validFiles = new DataTransfer();

        //Initialise Picker.
        this.input.onchange = () => {
            this.updateOutput();
            this.output.files = this.validFiles.files;
        }
    }

    updateOutput()
    {
        const files = Array.from(this.input.files);
        files.forEach((file) => {                
            let reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
                photo = this.createPhotoThumb({
                    url : reader.result,
                    name: file.name,
                    size: file.size
                });
                if (this.validatePhoto(file)) {
                    this.validFiles.items.add(file);
                };
            };
        });
    }

    createMarkUp()
    {
        //Creating needed HTML Markup
    }
    createPhotoThumb(data = {})
    {
        //Creating a photo thumbnail for preview
    }
    validatePhoto(photo)
    {
        //Validating the photo
    }
}

发生的事情是,当我第一次选择一些图像时,会显示缩略图,并且有效文件列表 this.validFiles.files 会更新,但是 NOT 我计划发送到服务器的最终列表 this.output.files 然而 ,在第二次尝试时,它成功了!最终列表更新为第一个选择的文件, NOT 第二个,依此类推。每次选择都更新前一个文件一个被添加到最终列表,但不是上次选择的文件。

我认为问题在于您期望

reader.onload = () => {
    photo = this.createPhotoThumb({
        url : reader.result,
        name: file.name,
        size: file.size
    });
    if (this.validatePhoto(file)) {
        this.validFiles.items.add(file);
    };
};

get 在您将有效文件分配给 this.output.files 之前执行。

但是 reader.onload 是异步执行的,因此您将有效文件分配给 this.output.files 会在将有效文件添加到有效文件数组之前执行。

您必须实现一些逻辑来等待读者的 onload 处理程序完成。

这可能是一个解决方案:

class PhotoPicker
{
    constructor(element)
    {
        this.element = element;

        // Creating needed HTML Markup
        this.createMarkUp();

        // FileList of valid data.
        this.validFiles = new DataTransfer();

        // Initialise Picker.
        this.input.onchange = () => {
            this.updateOutput()
                .then(() => {
                    this.output.files = this.validFiles.files;
                });
        }
    }

    updateOutput()
    {
        const files = Array.from(this.input.files);
        const fileLoaderPromises = [];
        files.forEach((file) => {
            const promise = new Promise((resolve) => {
                let reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onload = () => {
                    photo = this.createPhotoThumb({
                        url : reader.result,
                        name: file.name,
                        size: file.size
                    });
                    if (this.validatePhoto(file)) {
                        this.validFiles.items.add(file);
                    };
                    // Mark the file loader as "done"
                    resolve();
                };
            })

            // Add the promise to the list of file loader promises
            fileLoaderPromises.push(promise);
        });

        // Return a promise which resolves as soon as all file loader promises are done
        return Promise.all(fileLoaderPromises);
    }

    // ...
}