如何检测何时取消文件input点击?

如何检测用户何时使用html文件input取消文件input?

onChange让我检测到他们select文件的时间,但是我也想知道他们什么时候取消(closures文件select对话框而不select任何东西)。

虽然不是一个直接的解决scheme,也是不好的,因为它(只要我testing)与onfocus工作(需要一个相当有限的事件阻塞),你可以通过以下方法来实现它:

document.body.onfocus = function(){ /*rock it*/ } 

有什么好处的是,你可以附加/分离它与文件事件的时间,它似乎也适用于隐藏input(如果你使用可视变通办法蹩脚默认inputtypes=文件')。 之后,你只需要弄清楚input值是否改变。

一个例子:

 var godzilla = document.getElementById('godzilla') godzilla.onclick = charge function charge() { document.body.onfocus = roar console.log('chargin') } function roar() { if(godzilla.value.length) alert('ROAR! FILES!') else alert('*empty wheeze*') document.body.onfocus = null console.log('depleted') } 

看到它的行动: http : //jsfiddle.net/Shiboe/yuK3r/6/

可悲的是,它似乎只能在webkit浏览器上运行。 也许别人可以找出Firefox / IE解决scheme

你不能。

文件对话框的结果不会暴露给浏览器。

 /* Tested on Google Chrome */ $("input[type=file]").bind("change", function() { var selected_file_name = $(this).val(); if ( selected_file_name.length > 0 ) { /* Some file selected */ } else { /* No file selected or cancel/close dialog button clicked */ /* If user has select a file before, when they submit, it will treated as no file selected */ } }); 

当您select一个文件,然后单击打开/取消, input元素应该失去焦点aka blur 。 假设input的初始value空, blur处理程序中的任何非空值将指示OK,而空值将意味着“取消”。

更新:隐藏input时不会触发blur 。 因此,除非您想临时显示input ,否则不能使用基于IFRAME的上传的这个技巧。

如果您select与之前相同的文件,则可以捕获取消,并在此情况下单击“取消”。

你可以这样做:

 <input type="file" id="myinputfile"/> <script> document.getElementById('myinputfile').addEventListener('change', myMethod, false); function myMethod(evt) { var files = evt.target.files; f= files[0]; if (f==undefined) { // the user has clicked on cancel } else if (f.name.match(".*\.jpg")|| f.name.match(".*\.png")) { //.... the user has choosen an image file var reader = new FileReader(); reader.onload = function(evt) { try { myimage.src=evt.target.result; ... } catch (err) { ... } }; } reader.readAsDataURL(f); </script> 

只要听点击事件。

从Shiboe的例子来看,下面是一个jQuery的例子:

 var godzilla = $('#godzilla'); var godzillaBtn = $('#godzilla-btn'); godzillaBtn.on('click', function(){ godzilla.trigger('click'); }); godzilla.on('change click', function(){ if (godzilla.val() != '') { $('#state').html('You have chosen a Mech!'); } else { $('#state').html('Choose your Mech!'); } }); 

你可以在这里看到它的行动: http : //jsfiddle.net/T3Vwz

Shiboe的解决scheme将是一个很好的,如果它在移动webkit的工作,但事实并非如此。 我能想到的是在打开文件input窗口的时候向某个dom对象添加一个mousemove事件监听器,如下所示:

  $('.upload-progress').mousemove(function() { checkForFiles(this); }); checkForFiles = function(me) { var filefield = $('#myfileinput'); var files = filefield.get(0).files; if (files == undefined || files[0] == undefined) $(me).remove(); // user cancelled the upload }; 

当文件对话框打开时,鼠标移动事件在页面被阻止,当它closures时,检查文件input中是否有文件。 在我的情况下,我想要一个活动指标阻塞的东西,直到file upload,所以我只想取消我的指标。

然而,这并不能解决移动,因为没有鼠标移动。 我的解决scheme不够完美,但我认为它足够好。

  $('.upload-progress').bind('touchstart', function() { checkForFiles(this); }); 

现在我们正在屏幕上聆听相同的文件检查。 我非常有信心,取消后用户的手指会很快放在屏幕上,并closures此活动指示器。

也可以在文件input更改事件上添加活动指示器,但是在移动设备上,select映像和更改事件触发之间通常会有几秒钟的滞后,所以活动指示器的UX要好得多才能显示在过程的开始。

大多数这些解决scheme不适合我。

问题是你永远不知道哪一个事件会被触发,是click还是change ? 你不能假定任何顺序,因为它可能取决于浏览器的实现。

至less在Opera和Chrome(2015年末), click是在用文件填充input之前触发的,所以你永远不会知道files.length != 0的长度,直到你延迟clickchange后触发。

这是代码:

 var inputfile = $("#yourid"); inputfile.on("change click", function(ev){ if (ev.originalEvent != null){ console.log("OK clicked"); } document.body.onfocus = function(){ document.body.onfocus = null; setTimeout(function(){ if (inputfile.val().length === 0) console.log("Cancel clicked"); }, 1000); }; }); 

在我的情况下,我不得不隐藏提交button,而用户select图像。

这就是我想到的:

 $(document).on('click', '#image-field', function(e) { $('.submit-button').prop('disabled', true) }) $(document).on('focus', '#image-field'), function(e) { $('.submit-button').prop('disabled', false) }) 

#image-field是我的文件select器。 当没有人点击它,我禁用表单提交button。 关键是,当文件对话框closures – 无所谓他们select一个文件或取消 – #image-field的焦点回来,所以我听这个事件。

UPDATE

我发现,这在safari和poltergeist / phantomjs中不起作用。 如果你想实施这个信息,请考虑这个信息。

结合Shiboe和alx的解决scheme,我得到了最可靠的代码:

 var selector = $('<input/>') .attr({ /* just for example, use your own attributes */ "id": "FilesSelector", "name": "File", "type": "file", "contentEditable": "false" /* if you "click" on input via label, this prevents IE7-8 from just setting caret into file input's text filed*/ }) .on("click.filesSelector", function () { /* do some magic here, eg invoke callback for selection begin */ var cancelled = false; /* need this because .one calls handler once for each event type */ setTimeout(function () { $(document).one("mousemove.filesSelector focusin.filesSelector", function () { /* namespace is optional */ if (selector.val().length === 0 && !cancelled) { cancelled = true; /* prevent double cancel */ /* that's the point of cancel, */ } }); }, 1); /* 1 is enough as we just need to delay until first available tick */ }) .on("change.filesSelector", function () { /* do some magic here, eg invoke callback for successful selection */ }) .appendTo(yourHolder).end(); /* just for example */ 

一般情况下,mousemove事件会诀窍,但如果用户点击并比:

  • 取消文件打开对话框通过转义键(不移动鼠标),再次准确点击打开文件对话框再次…
  • 切换焦点到任何其他应用程序,比回到浏览器的文件打开对话框,并closures它,比input或空格键再次打开…

…我们不会得到mousemove事件,因此没有取消callback。 此外,如果用户取消第二个对话框,并使鼠标移动,我们会得到2取消callback。 幸运的是,在这两种情况下,特殊的jQuery focusIn事件都会冒泡到文档中,帮助我们避免出现这种情况。 唯一的限制是如果一个人阻止focusIn事件。

我看到我的回应会很过时,但从来不会less。 我面临同样的问题。 所以这是我的解决scheme。 最有用的代码是KGA的。 但它不完全工作,有点复杂。 但我简化了它。

另外,主要的麻烦制造者就是这个事实,那个“变化”事件并不是在焦点之后立即出现的,所以我们必须等待一段时间。

“#appendfile” – 哪个用户点击附加一个新文件。 Hrefs获得焦点事件。

 $("#appendfile").one("focusin", function () { // no matter - user uploaded file or canceled, // appendfile gets focus // change doesn't come instantly after focus, so we have to wait for some time // wrapper represents an element where a new file input is placed into setTimeout(function(){ if (wrapper.find("input.fileinput").val() != "") { // user has uploaded some file // add your logic for new file here } else { // user canceled file upload // you have to remove a fileinput element from DOM } }, 900); }); 

只有在有限的情况下才能检测到。 具体来说,在chrome中,如果之前select了文件,然后单击文件对话框并单击取消,则Chrome会清除该文件并触发onChange事件。

https://code.google.com/p/chromium/issues/detail?id=2508

在这种情况下,您可以通过处理onChange事件并检查文件属性来检测到此情况。

有一个hackish的方式来做到这一点(添加callback或解决一些延迟/承诺的实现,而不是alert()调用):

 var result = null; $('<input type="file" />') .on('change', function () { result = this.files[0]; alert('selected!'); }) .click(); setTimeout(function () { $(document).one('mousemove', function () { if (!result) { alert('cancelled'); } }); }, 1000); 

工作原理:文件select对话框打开时,文档不会收到鼠标指针事件。 有1000毫秒的延迟允许对话框实际出现并阻止浏览器窗口。 检入Chrome和Firefox(仅限Windows)。

但是,这当然不是检测取消对话的可靠方法。 虽然,可能会改善一些用户界面的行为。

这是我的解决scheme,使用文件input焦点(不使用任何定时器)

 var fileInputSelectionInitiated = false; function fileInputAnimationStart() { fileInputSelectionInitiated = true; if (!$("#image-selector-area-icon").hasClass("fa-spin")) $("#image-selector-area-icon").addClass("fa-spin"); if (!$("#image-selector-button-icon").hasClass("fa-spin")) $("#image-selector-button-icon").addClass("fa-spin"); } function fileInputAnimationStop() { fileInputSelectionInitiated = false; if ($("#image-selector-area-icon").hasClass("fa-spin")) $("#image-selector-area-icon").removeClass("fa-spin"); if ($("#image-selector-button-icon").hasClass("fa-spin")) $("#image-selector-button-icon").removeClass("fa-spin"); } $("#image-selector-area-wrapper").click(function (e) { $("#fileinput").focus(); $("#fileinput").click(); }); $("#preview-image-wrapper").click(function (e) { $("#fileinput").focus(); $("#fileinput").click(); }); $("#fileinput").click(function (e) { fileInputAnimationStart(); }); $("#fileinput").focus(function (e) { fileInputAnimationStop(); }); $("#fileinput").change(function(e) { // ... } 

这是最好的, 但这里是我的解决scheme的工作示例 ,以检测用户是否上传了一个文件,只允许他们继续上传文件。

基本上隐藏ContinueSaveProceed或任何你的button。 然后在JavaScript中抓取文件名。 如果文件名没有值,则不要显示“ Continuebutton。 如果它有一个值,然后显示button。 如果他们首先上传一个文件,然后他们尝试上传不同的文件,然后点击取消,这也是有效的。

这是代码。

HTML:

 <div class="container"> <div class="row"> <input class="file-input" type="file" accept="image/*" name="fileUpload" id="fileUpload" capture="camera"> <label for="fileUpload" id="file-upload-btn">Capture or Upload Photo</label> </div> <div class="row padding-top-two-em"> <input class="btn btn-success hidden" id="accept-btn" type="submit" value="Accept & Continue"/> <button class="btn btn-danger">Back</button> </div></div> 

JavaScript的:

 $('#fileUpload').change(function () { var fileName = $('#fileUpload').val(); if (fileName != "") { $('#file-upload-btn').html(fileName); $('#accept-btn').removeClass('hidden').addClass('show'); } else { $('#file-upload-btn').html("Upload File"); $('#accept-btn').addClass('hidden'); } }); 

CSS:

 .file-input { width: 0.1px; height: 0.1px; opacity: 0; overflow: hidden; position: absolute; z-index: -1; } .file-input + label { font-size: 1.25em; font-weight: normal; color: white; background-color: blue; display: inline-block; padding: 5px; } .file-input:focus + label, .file-input + label:hover { background-color: red; } .file-input + label { cursor: pointer; } .file-input + label * { pointer-events: none; } 

对于CSS来说,很多这是为了让所有人都可以访问网站和button。 将你的button设置为任何你喜欢的。

以下似乎为我工作(在桌面上,Windows):

 var openFile = function (mimeType, fileExtension) { var defer = $q.defer(); var uploadInput = document.createElement("input"); uploadInput.type = 'file'; uploadInput.accept = '.' + fileExtension + ',' + mimeType; var hasActivated = false; var hasChangedBeenCalled = false; var hasFocusBeenCalled = false; var focusCallback = function () { if (hasActivated) { hasFocusBeenCalled = true; document.removeEventListener('focus', focusCallback, true); setTimeout(function () { if (!hasChangedBeenCalled) { uploadInput.removeEventListener('change', changedCallback, true); defer.resolve(null); } }, 300); } }; var changedCallback = function () { uploadInput.removeEventListener('change', changedCallback, true); if (!hasFocusBeenCalled) { document.removeEventListener('focus', focusCallback, true); } hasChangedBeenCalled = true; if (uploadInput.files.length === 1) { //File picked var reader = new FileReader(); reader.onload = function (e) { defer.resolve(e.target.result); }; reader.readAsText(uploadInput.files[0]); } else { defer.resolve(null); } }; document.addEventListener('focus', focusCallback, true); //Detect cancel uploadInput.addEventListener('change', changedCallback, true); //Detect when a file is picked uploadInput.click(); hasActivated = true; return defer.promise; } 

这确实使用了angularjs $ q,但是如果需要的话,你应该可以用任何其他的promise框架replace它。

testingIE11,Edge,Chrome,Firefox,但是它似乎不适用于Android平板电脑上的Chrome,因为它不会触发Focus事件。

我发现这个属性,它最简单。

 if ($('#selectedFile')[0].files.length > 1) { // Clicked on 'open' with file } else { // Clicked on 'cancel' } 

在这里, selectedFile是一个input type=file

您可以在input字段上创build一个jQuery更改侦听器,并通过该字段的值检测该用户是否取消或closures上载窗口。

这里是一个例子:

 //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 } }); 

我需要这样做,我最终创build了一个非常简单的解决scheme。 可以在这里看到: http : //jsfiddle.net/elizeubh2006/1w711q0y/5/

(但只会在第一次select文件后才起作用,对我来说是非常有用的,因为即使用户点击取消,onchange事件也被调用,用户select了一个文件,然后点击select另一个文件,但取消了,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); } }); 

inputtypes=文件代码:

 onchange="if(this.files[0]!=undefined){ UploadImg(); }else{ alert('cancel'); }"