我正在使用标准的文件上传输入框,并寻找一种方法来将函数附加到事件上,当用户点击/按下“取消”按钮(或从“选择文件”对话框中退出)时触发。
我找不到在所有浏览器和平台上都能一致运行的事件。
我已经阅读了这个问题的答案:捕获input type=file上的cancel事件, 但它们并不起作用,因为大多数浏览器在取消选择文件对话框后不会触发change事件。
我正在寻找一个纯JS解决方案,但也接受jQuery解决方案。
有没有人成功解决这个问题?
我正在使用标准的文件上传输入框,并寻找一种方法来将函数附加到事件上,当用户点击/按下“取消”按钮(或从“选择文件”对话框中退出)时触发。
我找不到在所有浏览器和平台上都能一致运行的事件。
我已经阅读了这个问题的答案:捕获input type=file上的cancel事件, 但它们并不起作用,因为大多数浏览器在取消选择文件对话框后不会触发change事件。
我正在寻找一个纯JS解决方案,但也接受jQuery解决方案。
有没有人成功解决这个问题?
一些研究表明,无法检测在文件选择对话框窗口中选择“取消”时的操作。您可以使用 onchange
或 onblur
来检查是否已选择文件或是否已将某些内容添加到输入 value
中。
代码示例如下:https://jsfiddle.net/Twisty/j18td9cs/
HTML
<form>
Select File:
<input type="file" name="test1" id="testFile" />
<button type="reset" id="pseudoCancel">
Cancel
</button>
</form>
JavaScript
var inputElement = document.getElementById("testFile");
var cancelButton = document.getElementById("pseudoCancel");
var numFiles = 0;
inputElement.onclick = function(event) {
var target = event.target || event.srcElement;
console.log(target, "clicked.");
console.log(event);
if (target.value.length == 0) {
console.log("Suspect Cancel was hit, no files selected.");
cancelButton.onclick();
} else {
console.log("File selected: ", target.value);
numFiles = target.files.length;
}
}
inputElement.onchange = function(event) {
var target = event.target || event.srcElement;
console.log(target, "changed.");
console.log(event);
if (target.value.length == 0) {
console.log("Suspect Cancel was hit, no files selected.");
if (numFiles == target.files.length) {
cancelButton.onclick();
}
} else {
console.log("File selected: ", target.value);
numFiles = target.files.length;
}
}
inputElement.onblur = function(event) {
var target = event.target || event.srcElement;
console.log(target, "changed.");
console.log(event);
if (target.value.length == 0) {
console.log("Suspect Cancel was hit, no files selected.");
if (numFiles == target.files.length) {
cancelButton.onclick();
}
} else {
console.log("File selected: ", target.value);
numFiles = target.files.length;
}
}
cancelButton.onclick = function(event) {
console.log("Pseudo Cancel button clicked.");
}
我建议制作自己的取消或重置按钮,以重置表单或清除输入的值。
怀疑取消被点击,未选择任何文件。
和伪取消按钮已点击。
。在浏览对话框中单击取消时,什么也不会发生。如果之前选择了一个文件,一旦我点击“浏览”,它就会记录下我选择了先前的文件,即使我仍然在对话框中。 - Noitidartfocus
,然后是 blur
,最后如果用户选择了文件,则会触发 change
。因此,这里的 click
和 blur
事件会中断逻辑。更新后的 jQuery:https://jsfiddle.net/Twisty/btf1m9nc/ - Twisty我有一个完美的解决方案。
聚焦事件将在更改事件之前执行。
因此,我需要使用setTimeout方法使得focus方法比change方法晚执行。
const createUpload = () => {
let lock = false
return new Promise((resolve, reject) => {
// create input file
const el = document.createElement('input')
el.id = +new Date()
el.style.display = 'none'
el.setAttribute('type', 'file')
document.body.appendChild(el)
el.addEventListener('change', () => {
lock = true
const file = el.files[0]
resolve(file)
// remove dom
document.body.removeChild(document.getElementById(el.id))
}, { once: true })
// file blur
window.addEventListener('focus', () => {
setTimeout(() => {
if (!lock && document.getElementById(el.id)) {
reject(new Error('onblur'))
// remove dom
document.body.removeChild(document.getElementById(el.id))
}
}, 300)
}, { once: true })
// open file select box
el.click()
})
}
try {
const file = createUpload()
console.log(file)
} catch(e) {
console.log(e.message) // onblur
}
window
上的 focus
事件非常完美,您可以将整个内容包装在一个 Promise 中,并在用户取消文件选择时拒绝 Promise。 - Akash Kava现在在这种情况下触发了一个cancel
事件,自大约一年前起(对于Chrome和Firefox而言是两年),所有三个主要的浏览器引擎都支持。
document.querySelector("input").addEventListener("cancel", (evt) => {
console.log("You closed the file picker dialog without selecting a file.");
});
<input type="file">
oncancel
全局处理程序来检测此事件,因为这可能指向在<dialog>
元素上触发的同名事件,从而产生误报。据我所知,目前没有简单的检测方法。var isChrome = !!window.chrome;
window.addEventListener('focus', function (e) {
if(window.inputFileTrueClosed != false){
if(isChrome == true){
setTimeout(
function()
{
if(window.inputFileTrueClosed != false){
//if it is Chrome we have to wait because file.change(function(){... comes after "the window gets the focus"
window.inputFileTrueClosed = false;
}
}, 1000);
}
else
{
// if it is NOT Chrome (ex.Safari) do something when the "cancel" button is pressed.
window.inputFileTrueClosed = false;
}
}
})
Javascript
var currentEvent = "focus";
function onFileBrowse() {
var vtbFile = $('#uploadFile')[0].files[0];
if (vtbFile != undefined) {
var extension = vtbFile.name.split('.').pop().toLowerCase();
var valError = "";
if (extension === 'xlsx' || extension === 'xlsb' || extension === 'csv') {
if (vtbFile.size === 0)
valError = "File '" + vtbFile.name + "' is empty";
}
else
valError = "Extension '" + extension + "' is not supported.";
if (valError !== "") {
alert("There was an issue validating the file. " + valError, 20000);
}
}
//hide Indicator
var buttonUpload = document.getElementById('btnUploadTB');
buttonUpload.innerText = "Submit";
};
function fileClick() {
//show Indicator
var buttonUpload = document.getElementById('btnUploadTB');
buttonUpload.innerText = "Please wait..";
document.getElementById('uploadFile').value = null;
currentEvent = "click";
}
function fileFocus() {
currentEvent = "focus";
}
function fileBlur() {
if (!document.getElementById('uploadFile').value && currentEvent == "focus") {
console.log('blur' + 'change to submit');
//hide Indicator
var buttonUpload = document.getElementById('btnUploadTB');
buttonUpload.innerText = "Submit";
}
}
HTML
<input class="k-button k-upload-button" type="file" id="uploadFile" name="uploadFile"
accept=".csv,.xlsx,.xlsb" onChange='onFileBrowse()' onclick="fileClick()" onfocus="fileFocus()" onblur="fileBlur()" />
<button id="btnUploadTB" type="button" class="btn btn-default" onclick="uploadTBFile()" style="width:28%;margin-left: 3px;">Submit</button>
这段代码不会监听取消按钮是否被点击,但对我来说它是有效的。每次输入值发生变化时,它都会检查是否有文件附加在其上。从那里开始,我基本上可以做任何我需要做的事情。
$("#imageUpload").change(function() {
if (this.files && this.files[0]) {
console.log("Has file selected");
} else {
console.log("No file selected");
}
});
<input type="file" id="imageUpload" />
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
In react , on Change event of input field , the event has no files on cancel event, we can proceed with this assumption. Cancel event will be captured.
handleChange = (event) => {
console.log(event);
console.log(event.target.files[0]);
this.setState({
tableDataResult: false,
});
if(event.target.files[0]){
this.setState({
csvfile: event.target.files[0],
});
}else{
//Cancel event called
console.log("false");
this.setState({
csvfile: oldValue,
});
}
};
<input
style={{
width: "450px",
marginLeft: "15px",
marginTop: "5px",
}}
className="csv-input"
type="file"
ref={(input) => {
this.filesInput = input;
}}
name="file"
placeholder={null}
onChange={this.handleChange}
/>
$('#upload-portrait-input').on('change', function(){
if ( $(this).val() != '' )
{
$('#portraitForm').submit();
}
else { // do something when the user clicks cancel
}
});
这解决了我的问题,虽然除了Google Chrome之外没有在其他浏览器上进行测试:
$("#fileUpload").on("change", function (event) {
if (!$(this)[0].files[0]) {
event.preventDefault();
return;
};
// Else do something here.
});
$(this)[0]
是将jQuery对象转换为普通JavaScript对象。当您点击取消按钮时,files
的数组长度为零。您可以使用$(this)[0].files.length < 1
,或检查$(this)[0].files[0]
是否为undefined
。
$(this)[0]
- Jiří我需要在用户浏览文件资源管理器(活动/非活动)时以不同的方式设置我的文件上传样式。只有click
和blur
事件。请注意,当用户单击取消按钮时,需要在文件上传之外(在我的情况下是button
)单击。
这是我针对Angular的解决方案,但我想任何人都可以掌握这个想法,并使用您喜欢的框架/库/Vanilla JS进行调整。
<!-- HTML - Angular -->
<input hidden type="file" #fileInput (change)="onFileUpload($event.target.files)">
<button (click)="initBrowsingFlags(); fileInput.click()" (blur)="onBlur()" [class.browsing]="browsing">Upload</button>
// Typescript - Angular
/** Whether the user is browsing the file explorer. */
browsing = false;
/**
* If a 2nd `blur` event is emitted while {@link browsing} is still true, it means that the user
* clicked the Cancel button on the file explorer.
* */
alreadyOneBlurEventWhileBrowsing = false;
onFileUpload(files: FileList) {
// ...
this.resetBrowsingFlags();
}
onBlur() {
if (!this.browsing) return;
if (this.onCancelClickWhileBrowsing) {
this.resetBrowsingFlags();
} else {
this.onCancelClickWhileBrowsing = true;
}
}
initBrowsingFlags() {
this.browsing = true;
this.alreadyOneBlurEventWhileBrowsing= false;
}
resetBrowsingFlags() {
this.browsing = false;
this.alreadyOneBlurEventWhileBrowsing= false;
}
.change()
,所以应该寻找被调用的事件。有没有特定的浏览器您希望与之配合使用? - Twistyconfirm()
或prompt()
。 - Twisty