如何检测 <input type="file" /> 选择文件对话框上的取消按钮已被单击?

And*_*ndy 5 html javascript upload file typescript

为了处理网站上的文件上传,我们必须使用隐藏<input type="file" />元素。

要找出在“选择文件”对话框中选择了哪个文件,我们可以使用该onchange事件。

但是我们如何检测用户是否点击了取消按钮呢?不幸的是,没有任何oncancel活动。

有很多解决方法可以检测用户是否按下了取消按钮,但由于我在这里描述的问题,它们都没有可靠地为我工作。

And*_*ndy 8

我投入了无数的时间来寻找解决方案。现在我想与大家分享我的解决方案。

我使用三个事件处理程序:

  1. onchange文件输入上的事件:检测何时选择文件。

  2. onfocusevent on window:检测“选择文件”对话框何时关闭。

  3. onmousemoveevent on document.body:检测交互何时不再被阻止。只有当这个事件被调用时,才能确定onchange输入元素的事件被调用了。

前两点是显而易见的,您可以在大多数建议的解决方案中找到它们。onchange但关键点是第三点。在其他解决方案中,我有时会遇到这样的问题:我选择了一个文件,但在窗口获得焦点之前,该选定的文件尚未传播到事件处理程序。

长话短说,这是我的实现:

打字稿解决方案:

public static selectFile(accept: string = null): Promise<File> {
    return new Promise<File>(async resolve => {
        const fileInputElement = document.createElement('input') as HTMLInputElement;
        fileInputElement.type = 'file';
        fileInputElement.style.opacity = '0';
        if (accept) fileInputElement.accept = accept;
        fileInputElement.addEventListener('change', () => {
            const file = fileInputElement.files[0];
            console.log('File "' + file.name + '" selected.');
            document.body.removeChild(fileInputElement);
            resolve(file);
        });
        document.body.appendChild(fileInputElement);
        setTimeout(_ => {
            fileInputElement.click();
            const onFocus = () => {
                window.removeEventListener('focus', onFocus);
                document.body.addEventListener('mousemove', onMouseMove);
            };
            const onMouseMove = () => {
                document.body.removeEventListener('mousemove', onMouseMove);
                if (!fileInputElement.files.length) {
                    document.body.removeChild(fileInputElement);
                    console.log('No file selected.');
                    resolve(null);
                }
            }
            window.addEventListener('focus', onFocus);
        }, 0);
    });
}
Run Code Online (Sandbox Code Playgroud)

JavaScript 解决方案:

function selectFile(accept = null) {
    return new Promise(async resolve => {
        const fileInputElement = document.createElement('input');
        fileInputElement.type = 'file';
        fileInputElement.style.opacity = '0';
        if (accept) fileInputElement.accept = accept;
        fileInputElement.addEventListener('change', () => {
            const file = fileInputElement.files[0];
            console.log('File "' + file.name + '" selected.');
            document.body.removeChild(fileInputElement);
            resolve(file);
        });
        document.body.appendChild(fileInputElement);
        setTimeout(_ => {
            fileInputElement.click();
            const onFocus = () => {
                window.removeEventListener('focus', onFocus);
                document.body.addEventListener('mousemove', onMouseMove);
            };
            const onMouseMove = () => {
                document.body.removeEventListener('mousemove', onMouseMove);
                if (!fileInputElement.files.length) {
                    document.body.removeChild(fileInputElement);
                    console.log('No file selected.');
                    resolve(null);
                }
            }
            window.addEventListener('focus', onFocus);
        }, 0);
    });
}
Run Code Online (Sandbox Code Playgroud)