20240123----重返学习-原生js纯函数获取用户电脑上的文件
思路说明
- 通过外加点击后,通过监听这个DOM元素的change事件,在用户点击之后就能拿到用户电脑上的文件了。
- 通过原生js来动态创建type="file"的input元素,之后给监听该元素的change事件,同时手动用代码触发该元素的点击事件。后面在该元素的change事件中,就能拿到用户电脑上的文件。
- 但后面发现,用户打开弹窗但不先,并不会触发input元素的change事件,同时也不会触发type="file"的input元素的input事件。在MDN文档中,也没发现还有其它事件可以用。于是,在网上找到一个思路,就是用户选择文件或取消选择文件后,window会触发focus事件,可以在这里处理取消事件。
- 为让事件更纯粹,不造成负作用,要移除创建的input元素。同时,也要移除绑定到window上的focus事件。
- 为了稳定,返回的Promise的值一定会resolve掉,即如果用户不选或者选择文件出错,直接返回null。否则返回file类型的文件。
代码说明
const handleChooseFile = async function handleChooseFile() {
const thePromise = new Promise((resolve, reject) => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
const handleWindowFocus = () => {
const handleFileCancel = () => {
console.log('用户取消选择文件或选择文件出错');
resolve(null);
window.removeEventListener('focus', handleWindowFocus, false);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
};
setTimeout(handleFileCancel, 10000);
};
window.addEventListener('focus', handleWindowFocus, false);
const handleFileSelect = function handleFileSelect() {
console.log(`handleFileSelect-->`);
const selectedFile = fileInput.files ? fileInput.files[0] : null;
if (selectedFile) {
console.log('选择的文件:', selectedFile);
resolve(selectedFile);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
return;
}
console.log('用户取消选择文件或选择文件出错');
resolve(null);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
};
fileInput.addEventListener('change', handleFileSelect, false);
fileInput.click();
});
return thePromise;
};
handleChooseFile();
const handleChooseFile = async function handleChooseFile() {
const thePromise = new Promise<File | null>((resolve, reject) => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
const handleWindowFocus = () => {
const handleFileCancel = () => {
console.log('用户取消选择文件或选择文件出错');
resolve(null);
window.removeEventListener('focus', handleWindowFocus, false);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
};
setTimeout(handleFileCancel, 10000);
};
window.addEventListener('focus', handleWindowFocus, false);
const handleFileSelect = function handleFileSelect() {
console.log(`handleFileSelect-->`);
const selectedFile = fileInput.files ? fileInput.files[0] : null;
if (selectedFile) {
console.log('选择的文件:', selectedFile);
resolve(selectedFile);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
return;
}
console.log('用户取消选择文件或选择文件出错');
resolve(null);
if (document.body.contains(fileInput)) {
document.body.removeChild(fileInput);
}
};
fileInput.addEventListener('change', handleFileSelect, false);
fileInput.click();
});
return thePromise;
};
handleChooseFile();
进阶参考
- input file 文件框“取消”按钮事件
- 如何检测 html 的 input file 控件在文件输入时,用户点击了“取消;
- 监听 input type=file 文件上传取消事件;