我如何检测到 <input type="file" /> Select 文件对话框上的取消按钮已被单击?
How can I detect that the Cancel Button has been clicked on a <input type="file" /> Select File Dialog?
要处理网站上的文件上传,我们必须使用隐藏的 <input type="file" />
元素。
要找出在 Select 文件对话框中选择了什么文件,我们可以使用 onchange
事件。
但是我们如何检测用户是否点击了取消按钮?
不幸的是,没有 oncancel
事件。
有很多变通方法可以检测用户是否点击了取消按钮,但由于我描述的问题 here,其中 none 对我有效。
我投入了无数时间寻找解决方案。现在我想和你分享我的解决方案。
我使用三个事件处理程序:
onchange
文件输入事件:检测文件何时被选中。
onfocus
window
事件:检测 Select 文件对话框何时关闭。
onmousemove
document.body
事件:检测交互何时不再被阻止。只有调用了这个事件,才能确定input元素的onchange
事件已经被调用了
前两点很明显,您可以在大多数建议的解决方案中找到它们。但关键点是第 3 点。在其他解决方案中,我有时会遇到这样的问题:我选择了一个文件,但在 window 获得焦点之前,这个选定的文件尚未传播到 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);
});
}
要处理网站上的文件上传,我们必须使用隐藏的 <input type="file" />
元素。
要找出在 Select 文件对话框中选择了什么文件,我们可以使用 onchange
事件。
但是我们如何检测用户是否点击了取消按钮?
不幸的是,没有 oncancel
事件。
有很多变通方法可以检测用户是否点击了取消按钮,但由于我描述的问题 here,其中 none 对我有效。
我投入了无数时间寻找解决方案。现在我想和你分享我的解决方案。
我使用三个事件处理程序:
onchange
文件输入事件:检测文件何时被选中。onfocus
window
事件:检测 Select 文件对话框何时关闭。onmousemove
document.body
事件:检测交互何时不再被阻止。只有调用了这个事件,才能确定input元素的onchange
事件已经被调用了
前两点很明显,您可以在大多数建议的解决方案中找到它们。但关键点是第 3 点。在其他解决方案中,我有时会遇到这样的问题:我选择了一个文件,但在 window 获得焦点之前,这个选定的文件尚未传播到 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);
});
}