我正在使用标准的文件上传输入框,并寻找一种方法来将函数附加到事件上,当用户点击/按下“取消”按钮(或从“选择文件”对话框中退出)时触发。
我找不到在所有浏览器和平台上都能一致运行的事件。
我已经阅读了这个问题的答案:捕获input type=file上的cancel事件, 但它们并不起作用,因为大多数浏览器在取消选择文件对话框后不会触发change事件。
我正在寻找一个纯JS解决方案,但也接受jQuery解决方案。
有没有人成功解决这个问题?
我正在使用标准的文件上传输入框,并寻找一种方法来将函数附加到事件上,当用户点击/按下“取消”按钮(或从“选择文件”对话框中退出)时触发。
我找不到在所有浏览器和平台上都能一致运行的事件。
我已经阅读了这个问题的答案:捕获input type=file上的cancel事件, 但它们并不起作用,因为大多数浏览器在取消选择文件对话框后不会触发change事件。
我正在寻找一个纯JS解决方案,但也接受jQuery解决方案。
有没有人成功解决这个问题?
input.oncancel = (e) => { 不附加文件() }
- undefined如果你可以使用文件系统访问API的showOpenFilePicker
方法,那么有另一种选择。
在撰写本回答时,该API已经完全规范化,但只有Chromium浏览器(Chrome和Edge)支持,但希望它很快会更普遍可用。
(请注意,以下代码片段在沙箱或跨域iframe中不起作用,因此无法在StackOverflow、CodePen和jsfiddler上运行,您必须拥有HTTPS环境来进行测试)
document.querySelector("button").addEventListener("click", async () => {
try {
const file = await globalThis.showOpenFilePicker({
types: [
{
description: "Images",
accept: {
"image/*": [".png", ".gif", ".jpeg", ".jpg"],
},
}
]
});
console.log("You picked: ", file[0].name);
} catch (e) {
if (e.code === e.ABORT_ERR) {
alert("You cancelled.")
} else {
throw e;
}
}
});
<button>Pick a file</button>
function openFileOnClick(){
document.getElementById("fileSelector").value = "";
document.getElementById("fileSelector").files.length = 0;
document.getElementById("fileSelector").click();
if(document.getElementById("fileSelector").files.length >= 1){
alert(document.getElementById("fileSelector").value);
//Do something
}
else{
alert(document.getElementById("fileSelector").value);
//Cancel button has been called.
}
}
<html>
<head>
</head>
<body>
<input type="file" id="fileSelector" name="fileSelector" value="" style="display:none;" />
<input type="button" value="Open File" name="openFile" onclick="openFileOnClick();" />
</body>
</html>
focus
事件从未被触发。看起来Firefox使用了cancel
事件(更多信息请参见here)。我已经在最新版本的Chrome、Safari和Firefox中成功测试了这个功能:function selectFiles(
options?: {
/** Allow the selection of multiple files */
multiple?: boolean,
/** Restrict the selection to certain types of files (ex: `.txt`) */
accept?: Array<string>
}
): Promise<{
/** The list of selected files (empty if none selected) */
files: Array<File>,
/** The event that prompted the dialog to close */
event: Event
}> {
return new Promise((resolve) => {
const fileSelector: HTMLInputElement = document.createElement('input');
fileSelector.type = 'file';
fileSelector.style.display = 'none';
fileSelector.multiple = !!options?.multiple;
if (Array.isArray(options?.accept)) {
fileSelector.accept = options.accept.join(',');
}
let currTimeout;
const resolveWithFiles = (event?: Event) => {
clearTimeout(currTimeout);
currTimeout = setTimeout(() => {
// cleanup
window.removeEventListener('focus', resolveWithFiles);
fileSelector.remove();
// resolve with file array and the event associated with
// what prompted the dialog to close
resolve({ files: Array.from(fileSelector.files || []), event });
}, 300);
};
// EVENTS
// "cancel" event in Chrome and Safari
window.addEventListener('focus', resolveWithFiles);
// "cancel" event in Firefox
fileSelector.addEventListener('cancel', resolveWithFiles);
// files selected
fileSelector.addEventListener('change', resolveWithFiles);
// INITIATE
// open the selection window
document.body.append(fileSelector);
fileSelector.click();
});
}
// wait function to delay
const wait = (ms) => new Promise((res) => setTimeout(res, ms));
class FilePickerServiceK {
getFileInput() {
if (this.ref)
return this.ref;
const input = document.createElement('input');
input.type = 'file';
this.ref = input;
return this.ref;
}
async pick(opt = {}) {
const input = this.getFileInput();
input.multiple = opt.multiple;
const onWindowFocusP = new Promise((res) => window.addEventListener('focus', res, {once: true}));
input.click();
await onWindowFocusP;
await wait(100);
const files = Array.from(input.files ?? []);
input.value = '';
return files;
}
}
const FilePickerService = new FilePickerServiceK();
// for demo
const button = document.createElement('button');
button.innerHTML = 'Pick File';
document.body.appendChild(button);
const div = document.createElement('div');
document.body.appendChild(div);
const handle = async () => {
const [file] = await FilePickerService.pick();
div.innerHTML = file ? file.name : 'cancelled';
};
button.addEventListener('click', handle);
$("input[type='file']").on('change', changeCB);
function changeCB(ev){
if (this.files && this.files.length > 0) {
// upload new file
alert('upload');
} else {
// cancel upload no files received when event change casted
alert('cancel');
}
}
this.files.length
将等于 0。
.change()
,所以应该寻找被调用的事件。有没有特定的浏览器您希望与之配合使用? - Twistyconfirm()
或prompt()
。 - Twisty