如何检测何时单击文件输入的取消?
Posted
技术标签:
【中文标题】如何检测何时单击文件输入的取消?【英文标题】:How to detect when cancel is clicked on file input? 【发布时间】:2011-06-05 10:33:02 【问题描述】:如何检测用户何时使用 html 文件输入取消文件输入?
onChange 让我检测他们何时选择文件,但我也想知道他们何时取消(关闭文件选择对话框而不选择任何内容)。
【问题讨论】:
您也可以检测是否有人选择了文件,然后尝试选择发送但取消,您将得到空e.target.files
请你接受一个答案....
【参考方案1】:
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>
【讨论】:
仅代码的答案被认为是低质量的:请务必说明您的代码的作用以及它如何解决问题。如果您可以在帖子中添加更多信息,它将帮助提问者和未来的读者。见Explaining entirely code-based answers【参考方案2】:很多人一直建议更改事件...即使 OP 指定这在问题中不起作用:
单击取消不会选择文件,因此不会触发对文件输入的更改!!!
大多数人建议的所有代码都不会在单击取消时运行。
根据实际阅读 OP 问题的人的建议进行了大量实验后,我提出了这个类来包装文件输入的功能并添加了两个自定义事件:
选择:用户选择了一个文件(如果他们选择了仍然触发 同一个文件)。 cancel:用户已单击取消或以其他方式关闭文件 没有选择的对话框。我还添加了冗余(监听多个事件以尝试确定是否按下了取消)。可能不会总是立即响应,但至少应该保证在用户重新访问页面时注册取消事件。
最后我注意到事件并不总是保证以相同的顺序发生(尤其是当对话框关闭几乎同时触发它们时)。此类在检查成功标志之前等待 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 回来。
【讨论】:
试过这个类,它每次在 Chrome 中触发取消事件,从不触发选择事件。 @RyanMann 奇怪,我已经在 FF、Chrome 和 Edge 中进行了测试,它似乎对我有用。我建议您尝试将延迟从“100ms”增加到“200ms”。我怀疑更改正在触发,但它花费的时间超过 100 毫秒,因此首先触发了取消。 Lmk 是否可行,我也许可以提出其他建议。 谢谢,我已经厌倦了处理它,所以我只是重新设计了我的工作流程,不需要知道是否点击了取消。我想知道是否单击了取消,以便我可以停止显示模态叠加加载窗口。所以我只是将其更改为在更改事件中出现新文件之前不显示覆盖。【参考方案3】:您可以在输入字段上创建一个 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
);
【讨论】:
不知道为什么这被否决了——这就是我想要的。谢谢! ?【参考方案4】:我需要这样做,我最终创建了一个非常简单的解决方案。可以看这里: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);
);
【讨论】:
很遗憾,这不适用于 ios 移动 Safari。 它不起作用,因为只有在选择文件时才会触发更改,而且所选文件应该与以前选择的文件不同。 "只有在第一次选择文件后才能工作" -> jsfiddle.net/elizeubh2006/1w711q0y/5 “仅在第一次选择后才有效” 有多少人甚至不看这个问题并试图回答它?... OP 想要一个取消按钮的事件而不是文件更改。取消不会触发更改事件。如果用户取消它,您的代码将永远不会运行。以上是关于如何检测何时单击文件输入的取消?的主要内容,如果未能解决你的问题,请参考以下文章