【发布时间】:2011-06-05 10:33:02
【问题描述】:
如何检测用户何时使用 html 文件输入取消文件输入?
onChange 让我检测他们何时选择文件,但我也想知道他们何时取消(关闭文件选择对话框而不选择任何内容)。
【问题讨论】:
-
您也可以检测是否有人选择了文件,然后尝试选择发送但取消,您将得到空
e.target.files -
请你接受一个答案....
如何检测用户何时使用 html 文件输入取消文件输入?
onChange 让我检测他们何时选择文件,但我也想知道他们何时取消(关闭文件选择对话框而不选择任何内容)。
【问题讨论】:
e.target.files
enter code here
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<h1>Hello</h1>
<div id="cancel01">
<button>Cancel</button>
</div>
<div id="cancel02">
<button>Cancel</button>
</div>
<div id="cancel03">
<button>Cancel</button>
</div>
<form>
<input type="file" name="name" placeholder="Name" />
</form>
<script>
const nameInput = document.querySelector('input[type="file"]');
/******
*The below code if for How to detect when cancel is clicked on file input
******/
nameInput.addEventListener('keydown', e => {
/******
*If the cancel button is clicked,then you should change the input file value to empty
******/
if (e.key == 'Backspace' || e.code == 'Backspace' || e.keyCode == 8) {
console.log(e);
/******
*The below code will delete the file path
******/
nameInput.value = '';
}
});
</script>
</body>
</html>
【讨论】:
很多人一直建议更改事件...即使 OP 指定这在问题中不起作用:
单击取消不会选择文件,因此不会触发对文件输入的更改!!!
大多数人建议的所有代码都不会在单击取消时运行。
根据实际阅读 OP 问题的人的建议进行了大量实验后,我提出了这个类来包装文件输入的功能并添加了两个自定义事件:
我还添加了冗余(监听多个事件以尝试确定是否按下了取消)。可能不会总是立即响应,但至少应该保证在用户重新访问页面时注册取消事件。
最后我注意到事件并不总是保证以相同的顺序发生(尤其是当对话框关闭几乎同时触发它们时)。此类在检查成功标志之前等待 100 毫秒以确保更改事件已触发。
使用 ES6 类,所以在此之前可能无法用于任何东西,但如果你想浪费时间让它在 IE 上运行,你可以编辑它?。
班级:
class FileManager {
// Keep important properties from being overwritten
constructor() {
Object.defineProperties(this, {
// The file input element (hidden)
_fileInput: {
value: document.createElement('input'),
writeable: false,
enumerable: false,
configurable: false
},
// Flag to denote if a file was chosen
_chooseSuccess: {
value: false,
writable: true,
},
// Keeps events from mult-firing
// Don't want to consume just incase!
_eventFiredOnce: {
value: false,
writable: true,
},
// Called BEFORE dialog is shown
_chooseStart_handler: {
value: (event) => {
// Choose might happen, assume it won't
this._chooseSuccess = false;
// Allow a single fire
this._eventFiredOnce = false;
// Reset value so repeat files also trigger a change/choose
this._fileInput.value = '';
/* File chooser is semi-modal and will stall events while it's opened */
/* Beware, some code can still run while the dialog is opened! */
// Window will usually focus on dialog close
// If it works this is best becuase the event will trigger as soon as the dialog is closed
// Even the user has moved the dialog off of the browser window is should still refocus
window.addEventListener('focus', this._chooseEnd_handler);
// This will always fire when the mouse first enters the body
// A good redundancy but will not fire immeditely if the cance button is not...
// in window when clicked
document.body.addEventListener('mouseenter', this._chooseEnd_handler);
// Again almost a guarantee that this will fire but it will not do so...
// imediately if the dialog is out of window!
window.addEventListener('mousemove', this._chooseEnd_handler);
},
writeable: false,
enumerable: false,
configurable: false
},
_chooseEnd_handler: {
// Focus event may beat change event
// Wait 1/10th of a second to make sure change registers!
value: (event) => {
// queue one event to fire
if (this._eventFiredOnce)
return;
// Mark event as fired once
this._eventFiredOnce = true;
// double call prevents 'this' context swap, IHT!
setTimeout((event) => {
this._timeout_handler(event);
}, 100);
},
writeable: false,
enumerable: false,
configurable: false
},
_choose_handler: {
value: (event) => {
// A file was chosen by the user
// Set flag
this._chooseSuccess = true;
// End the choose
this._chooseEnd_handler(event);
},
writeable: false,
enumerable: false,
configurable: false
},
_timeout_handler: {
value: (event) => {
if (!this._chooseSuccess) {
// Choose process done, no file selected
// Fire cancel event on input
this._fileInput.dispatchEvent(new Event('cancel'));
} else {
// Choose process done, file was selected
// Fire chosen event on input
this._fileInput.dispatchEvent(new Event('choose'));
}
// remove listeners or cancel will keep firing
window.removeEventListener('focus', this._chooseEnd_handler);
document.body.removeEventListener('mouseenter', this._chooseEnd_handler);
window.removeEventListener('mousemove', this._chooseEnd_handler);
},
writeable: false,
enumerable: false,
configurable: false
},
addEventListener: {
value: (type, handle) => {
this._fileInput.addEventListener(type, handle);
},
writeable: false,
enumerable: false,
configurable: false
},
removeEventListener: {
value: (type, handle) => {
this._fileInput.removeEventListener(type, handle);
},
writeable: false,
enumerable: false,
configurable: false
},
// Note: Shadow clicks must be called from a user input event stack!
openFile: {
value: () => {
// Trigger custom pre-click event
this._chooseStart_handler();
// Show file dialog
this._fileInput.click();
// ^^^ Code will still run after this part (non halting)
// Events will not trigger though until the dialog is closed
}
}
});
this._fileInput.type = 'file';
this._fileInput.addEventListener('change', this._choose_handler);
}
// Get all files
get files() {
return this._input.files;
}
// Get input element (reccomended to keep hidden);
get domElement(){
return this._fileInput;
}
// Get specific file
getFile(index) {
return index === undefined ? this._fileInput.files[0] : this._fileInput.files[index];
}
// Set multi-select
set multiSelect(value) {
let val = value ? 'multiple' : '';
this._fileInput.setAttribute('multiple', val);
}
// Get multi-select
get multiSelect() {
return this._fileInput.multiple === 'multiple' ? true : false;
}
}
用法示例:
// Instantiate
let fm = new FileManager();
// Bind to something that triggers a user input event (buttons are good)
let btn = document.getElementById('btn');
// Call openFile on intance to show the dialog to the user
btn.addEventListener('click', (event) => {
fm.openFile();
});
// Fires if the user selects a file and clicks the 'okay' button
fm.addEventListener('choose', (event) => {
console.log('file chosen: ' + fm.getFile(0).name);
});
// Fires if the user clicks 'cancel' or closes the file dialog
fm.addEventListener('cancel', (event) => {
console.log('File choose has been canceled!');
});
可能为时已晚,但我认为这是一个不错的解决方案,涵盖了大多数严重的边缘情况。我将自己使用这个解决方案,所以在我使用它并进一步完善它之后,我最终可能会带着一个 git repo 回来。
【讨论】:
您可以在输入字段上创建一个 jquery 更改侦听器,并通过该字段的值检测用户取消或关闭上传窗口。
这是一个例子:
//when upload button change
$('#upload_btn').change(function(){
//get uploaded file
var file = this.files[0];
//if user choosed a file
if(file){
//upload file or perform your desired functiuonality
}else{
//user click cancel or close the upload window
}
});
【讨论】:
我需要这样做,我最终创建了一个非常简单的解决方案。可以看这里:http://jsfiddle.net/elizeubh2006/1w711q0y/5/
(但只有在第一次选择文件后才会起作用。对我来说这很有用,因为即使用户单击取消也会调用 onchange 事件。用户选择了一个文件,然后单击以选择另一个文件,但取消了并调用了 onchange。)
$("#inputFileId").on("change", function() {
var x = document.getElementById('inputFileId');
if(x.files.length == 0)
{
alert('cancel was pressed');
}
else
{
alert(x.files[0].name);
}
});
【讨论】: