我已经花费无数个小时寻找解决方案。现在我想与您分享我的解决方案。
我使用了三个事件处理程序:
文件输入的onchange
事件:用于检测是否选择了文件。
window
上的onfocus
事件:用于检测选择文件对话框何时关闭。
document.body
上的onmousemove
事件:用于检测交互是否不再被阻塞。只有当调用此事件时,您才可以确定输入元素的onchange
事件已被调用。
前两个点很明显,您会在大多数提议的解决方案中找到它们。但是关键点是第三点。在其他解决方案中,我有时会遇到这样的问题:我选择了一个文件,但在窗口获取焦点之前,这个选定的文件还没有传播到onchange
事件处理程序。
长话短说,这是我的实现:
TypeScript解决方案:
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);
});
}
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);
});
}
change
事件似乎没有足够的时间传播,控制台会打印出“未选择文件”。 - AlexandreS