如何检测何时在文件输入上单击了取消?


112

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

onChange可让我检测他们何时选择文件,但是我也想知道他们何时取消(关闭文件选择对话框而不选择任何内容)。


您还可以检测是否有人选择了文件,然后尝试选择发送但被取消的文件,您会得到空的e.target.files
jcubic

Answers:


45

虽然这不是直接的解决方案,但也很糟糕,它仅(就我所测试的而言)与onfocus一起使用(需要相当大的事件限制),您可以使用以下方法实现此目的:

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

这样做的好处是,您可以在文件事件中及时附加/分离它,并且它对于隐藏的输入似乎也可以很好地工作(如果您对the脚的默认输入类型使用可视化解决方法,则可以肯定地得到了回报。文件')。之后,您只需要确定输入值是否已更改。

一个例子:

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解决方案


我不想每次都触发焦点事件,所以我想使用addEventListener("focus",fn,{once: true})。但是我无法使用document.body.addEventListener..我完全不知道为什么。相反,我得到与相同的结果window.addEventListener
WoodenKitty

3
对我来说,这在Firefox和Edge中不起作用。然而,监听mousemove事件上window.document ,除了要听focuswindow似乎到处工作(至少在现代浏览器,我不关心过去十年的残骸)。基本上,任何交互事件都可以用于此任务,该事件被打开的文件打开对话框阻止。
John Weisz

@WoodenKitty您如何使用addEventListener实现此功能。我试图做这一点-在角度和document.body的心不是我的工作
特伦斯·杰克逊

这在隐藏的输入字段上不起作用。
塞巴斯蒂安

20

你不能

文件对话框的结果不会显示给浏览器。


是否可以检查文件选择器是否打开?
Ppp

1
@Ppp-不。浏览器不会告诉您。
Oded

6
“文件对话框的结果不会显示给浏览器。” 如果通过选择文件关闭对话框,则情况并非如此。
特雷弗

3
使用文件对话框触发的更改将显示给浏览器。请参阅,如果没有选择文件,并且此后也没有选择文件,则什么都没有改变,因此不会change调度事件。
约翰·魏茨

1
此外,如果已经选择了一个文件,然后再次选择同一文件,则不会change为该事件调度任何事件。
Patrick Roberts

16

因此,自从我提出了一个新颖的解决方案以来,我将对此表示怀疑。我有一个渐进式Web应用程序,允许用户捕获照片和视频并上传它们。我们在可能的情况下使用WebRTC,但对于支持较少的设备,请改用HTML5文件选择器*咳嗽Safari咳嗽*。如果您专门在使用本机相机直接捕获照片/视频的Android / iOS移动Web应用程序上工作,那么这是我遇到的最好的解决方案。

这个问题的症结在于,页面加载时,fileis是null,但是当用户打开对话框并按“ Cancel”时,fileis仍然是null,因此它没有“更改”,因此不会触发“更改”事件。对于台式机来说,这还算不错,因为大多数台式机UI并不依赖于知道何时调用取消,但是带动相机捕获照片/视频的移动UI却非常依赖于何时按下取消。

我最初使用该document.body.onfocus事件来检测用户何时从文件选择器返回,并且该方法适用于大多数设备,但是iOS 11.3破坏了该事件,因为未触发该事件。

概念

我的解决方案是* shudder *,以测量CPU时序以确定当前页面是在前台还是在后台。在移动设备上,将处理时间分配给当前位于前台的应用程序。当摄像机可见时,它将占用CPU时间并降低浏览器的优先级。我们需要做的就是测量给页面多少处理时间,当相机启动时,我们的可用时间将大大减少。关闭相机(取消或取消相机)后,我们的可用时间会重新增加。

实作

我们可以通过使用setTimeout()X毫秒来调用回调来测量CPU时序,然后测量实际调用它所花费的时间。浏览器永远不会在X毫秒之后精确地调用它,但是如果可以关闭,则我们必须处于前台。如果浏览器距离很远(比要求的速度慢10倍以上),那么我们必须在后台。这样的基本实现是这样的:

function waitForCameraDismiss() {
  const REQUESTED_DELAY_MS = 25;
  const ALLOWED_MARGIN_OF_ERROR_MS = 25;
  const MAX_REASONABLE_DELAY_MS =
      REQUESTED_DELAY_MS + ALLOWED_MARGIN_OF_ERROR_MS;
  const MAX_TRIALS_TO_RECORD = 10;

  const triggerDelays = [];
  let lastTriggerTime = Date.now();

  return new Promise((resolve) => {
    const evtTimer = () => {
      // Add the time since the last run
      const now = Date.now();
      triggerDelays.push(now - lastTriggerTime);
      lastTriggerTime = now;

      // Wait until we have enough trials before interpreting them.
      if (triggerDelays.length < MAX_TRIALS_TO_RECORD) {
        window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
        return;
      }

      // Only maintain the last few event delays as trials so as not
      // to penalize a long time in the camera and to avoid exploding
      // memory.
      if (triggerDelays.length > MAX_TRIALS_TO_RECORD) {
        triggerDelays.shift();
      }

      // Compute the average of all trials. If it is outside the
      // acceptable margin of error, then the user must have the
      // camera open. If it is within the margin of error, then the
      // user must have dismissed the camera and returned to the page.
      const averageDelay =
          triggerDelays.reduce((l, r) => l + r) / triggerDelays.length
      if (averageDelay < MAX_REASONABLE_DELAY_MS) {
        // Beyond any reasonable doubt, the user has returned from the
        // camera
        resolve();
      } else {
        // Probably not returned from camera, run another trial.
        window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
      }
    };
    window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
  });
}

我在最新版本的iOS和Android上对此进行了测试,通过在<input />元素上设置属性来调出本机相机。

<input type="file" accept="image/*" capture="camera" />
<input type="file" accept="video/*" capture="camcorder" />

这实际上比我预期的要好得多。它通过请求在25毫秒内调用计时器来运行10次试用。然后,它测量实际调用所需的时间,如果10次尝试的平均时间少于50毫秒,则我们假定必须处于前台并且相机已关闭。如果大于50毫秒,那么我们必须仍然在后台并且应该继续等待。

一些其他细节

我之所以使用setTimeout()它,不是setInterval()因为后者可以将多个调用排入队列,这些调用彼此之后立即执行。这可能会大大增加数据中的噪声,因此我坚持这样做,setTimeout()尽管这样做要复杂一些。

这些特殊的数字对我来说效果很好,尽管我至少看到过一次相机过早熄灭的情况。我认为这是因为相机打开速度可能很慢,并且该设备可能在实际变为背景之前进行了10次试用。添加更多试用版或等待25至50毫秒才能启动此功能,可能是一种解决方法。

桌面

不幸的是,这对于台式机浏览器实际上并不起作用。从理论上讲,相同的技巧是可能的,因为它们的确将当前页面置于后台页面之上。但是,许多台式机具有足够的资源,即使在后台运行时也可以保持页面全速运行,因此这种策略在实践中实际上并不起作用。

替代解决方案

很少有人提到我确实探索过的另一种解决方案是模拟FileList。我们开始null<input />后,如果用户打开摄像头,并取消他们回来null,这是不发生变化,没有事件将触发。一种解决方案是将一个虚拟文件分配给<input />页面开始处,因此将设置为null将触发适当事件的更改。

不幸的是,没有正式的方法来创建FileList,并且<input />元素FileList特别需要a ,并且除了以外将不接受任何其他值null。自然地,FileList对象不能直接构造,可以解决一些旧的安全问题,这些问题显然不再相关。保持<input />元素外部唯一的方法是利用一种黑客技术,该技术通过复制粘贴数据来伪造可能包含一个FileList对象的剪贴板事件(您基本上是在伪造一个拖放文件, -您的网站事件)。这在Firefox中是可行的,但对于iOS Safari则不可行,因此在我的特定用例中不可行。

浏览器,请...

不用说这显然是荒谬的。网页的关键用户界面元素已更改为零通知这一事实简直是可笑的。这确实是规范中的错误,因为它原本不打算用于全屏媒体捕获UI,并且从技术上讲,不触发“ change”事件是技术上的规范。

但是,浏览器供应商能否认识到这一现实?这可以通过新的“完成”事件来解决,即使没有发生更改也可以触发该事件,或者无论如何您都可以触发“更改”。是的,这违背了规范,但是对于我而言,在JavaScript方面简化变更事件是微不足道的,但是从根本上来说,不可能发明自己的“完成”事件。如果不保证浏览器的状态,即使我的解决方案实际上也只是试探法。

就目前而言,此API从根本上讲不适用于移动设备,而且我认为相对简单的浏览器更改可能会使Web开发人员无限轻松地“摆脱肥皂盒”。



7

当您选择一个文件并单击“打开/取消”时,该input元素也应该失去焦点blur。假设初始valueinput是空的,在你的任何非空值的blur处理程序将指示OK,和一个空值将意味着取消。

更新:隐藏blur时不会触发input。因此,除非要临时显示,否则不能将其用于基于IFRAME的上传input


3
在Firefox 10 beta和Chrome 16中,blur选择文件时不会触发。尚未在其他浏览器中尝试过。
布莱斯2012年

1
这不起作用-点击后立即触发输入模糊。在Win7上使用Chrome 63.0.3239.84 x64。
Qwertiy

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

6
您是否检查else过您的陈述是否得到过评估?
jayarjo,2013年

据我记得我写这个答案时,如果用户选择一个文件然后重新选择该文件(但随后取消),则将其视为未选择文件,我仅在selected_file_name变量上使用alert对其进行测试。无论如何,从那以后就再也没有测试过了。
黎兹基

4
我可以说,经过一些跨浏览器测试,Firefox不会在cancel时触发更改事件,如果重新打开并第二次单击cancel,它也不会清除所选的现有文件。奇怪吧
mix3d

7

这些解决方案大多数都不适合我。

问题是,你永远不知道这将触发事件的拳头,是它click还是它change?您不能假设任何顺序,因为它可能取决于浏览器的实现。

至少在Opera和Chrome浏览器中(2015年末)click是在文件“填充”输入之前触发的,因此files.length != 0直到延迟click触发之后,您才知道它的长度change

这是代码:

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

如果单击页面上的“取消单击” ... = | (已通过Chrome测试)
Eduardo Lucio

5

只需听一下click事件。

在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


1
我在Chrome 51上进行了测试,但是第一次选择文件时却无法使用。解决方案是增加延迟:jsfiddle.net/7jfbmunh
Benoit Blanchon

您的小提琴对我不起作用-使用Firefox 58.0.2
barrypicker

4

如果选择与以前相同的文件,然后单击“取消”,则可以捕获取消:在这种情况下。

您可以这样做:

<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>

1
Thnkx @loveJs这篇文章确实对我有所帮助。
VPK

4
不完全相同,如果用户选择相同的文件,则不是取消=(
Tiago PeresFrança2013年

13
onchange仅在发生更改时才会触发。因此,如果文件与以前的文件相同,则不会触发onchange侦听器。
Shane

1
您可以在检测到第一个更改后清除输入选择(input.value =''),以便即使用户再次选择相同文件,也将触发第二次onchange。
克里斯(Chris)

1
@CodeGems允许以编程方式将input.value设置为空字符串。但是您是正确的,不允许将其设置为任何其他值。
克里斯(Chris)

4

最简单的方法是检查临时内存中是否有文件。如果您希望每次用户单击文件输入时都获得更改事件,则可以触发它。

var yourFileInput = $("#yourFileInput");

yourFileInput.on('mouseup', function() {
    $(this).trigger("change");
}).on('change', function() {
    if (this.files.length) {
        //User chose a picture
    } else {
        //User clicked cancel
    }
});

2

如果Shiboe的解决方案适用于移动Webkit,那将是一个很好的解决方案,但事实并非如此。我能想到的是在打开文件输入窗口时向某些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
      };

在打开文件对话框时,以及在关闭对话框时,mousemove事件都被阻止在页面上,以检查文件输入中是否有文件。就我而言,我想要一个活动指示器来阻止事物直到文件被上传,所以我只想在取消时删除我的指示器。

但是,这对于移动设备并不能解决,因为没有鼠标可以移动。我的解决方案还不够完美,但我认为它已经足够好了。

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

现在,我们正在听屏幕上的触摸以进行相同的文件检查。我非常有信心,取消并取消此活动指示器后,用户的手指将很快出现在屏幕上。

也可以将活动指示器添加到文件输入更改事件上,但是在移动设备上,选择图片和更改事件触发之间通常会间隔几秒钟,因此在活动指示器上显示活动指示器要好得多该过程的开始。


2

我找到了这个属性,它是最简单的。

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

selectedFile是一个input type=file


这对我来说是一个很好的解决方案,除了它应该> = 1
Bron Thulke '17

2

我知道这是一个非常老的问题,但是为了以防万一,当我使用onmousemove事件检测取消时,发现有必要在短时间内测试两个或多个此类事件。这是因为每次将光标移出选择文件对话框窗口时,以及每次将其移出主窗口再移回时,浏览器(Chrome 65)都会生成单个onmousemove事件。鼠标移动事件的简单计数器再加上短暂的超时,以将计数器重置为零,这是一种享受。


1
第一段是一个很好的答案,即使可以将其拆分为多个段以提高可读性。但是这两个“ SOAPBOX”行使它成为“不回答”的边界,因为问题不属于答案。您可以改写/重新措词一下吗?谢谢。
Filnor

1

就我而言,我必须在用户选择图像时隐藏提交按钮。

这就是我的想法:

$(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是我的文件选择器。当有人单击它时,我禁用了表单提交按钮。关键是,当文件对话框关闭时-不管他们选择文件还是取消-都重新#image-field获得了焦点,所以我听那个事件。

更新

我发现,这在Safari和poltergeist / phantomjs中不起作用。如果您想实施此信息,请考虑在内。


1

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

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, e.g. 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, e.g. invoke callback for successful selection */
   })
   .appendTo(yourHolder).end(); /* just for example */

通常,mousemove事件可以解决问题,但如果用户单击并导致以下事件:

  • 通过退出键(不移动鼠标)取消了文件打开对话框,再次单击准确再次打开文件对话框...
  • 将焦点切换到任何其他应用程序,然后返回浏览器的文件打开对话框并关闭它,然后通过Enter或空格键再次打开...

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


在Ubuntu 16.10的Chrome 56.0.2924.87的OS对话框中选择文件的过程中,我捕获了该mousemove事件document。没问题,不移动鼠标或仅使用键盘选择文件。我不得不更换mousemovekeydown检测尽早取消,但不能“太早”,当对话框仍然开放。
费迪南德·普兰特

1

我看到我的回应会很过时,但永远不会少。我面临着同样的问题。所以这是我的解决方案。最有用的代码是KGA的代码。但是它不能完全正常工作,并且有点复杂。但是我简化了。

同样,主要的麻烦制造者是这样一个事实,即“改变”事件并不是在聚焦后立即发生的,因此我们必须等待一段时间。

“ #appendfile”-用户单击以添加新文件。Href获得焦点事件。

$("#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);
});

1

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

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

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


1

以下似乎适用于我(在台式机,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框架。

在IE11,Edge,Chrome,Firefox上进行了测试,但由于它不会触发Focus事件,因此它似乎无法在Android Tablet上的Chrome上运行。


1

file型字段,令人沮丧的,并没有很多的事件(模糊是可爱的)响应。我看到很多人都在建议change面向解决方案,但他们却被否决了。

change确实有效,但是它有一个主要缺陷(与我们发生的事情相比)。

重新加载包含文件字段的页面时,请打开该框,然后按“取消”。令人沮丧的是,没有任何变化

我选择做的是在门控状态下加载。

  • section#after-image在我的情况下,表单a的下一部分从视图中隐藏了。当我的file field变化,上传按钮显示。成功上传后,section#after-image显示。
  • 如果用户加载,打开文件对话框,然后取消,他们将永远不会看到上传按钮。
  • 如果用户选择文件,则会显示上载按钮。如果他们随后打开对话框并取消,则change此取消会触发该事件,然后我可以(并确实)重新隐藏我的上传按钮,直到选择了正确的文件为止。

我很幸运,这个门控状态已经是我表单的设计。您不需要使用相同的样式,只需先隐藏上传按钮,然后进行更改即可,将隐藏字段或javascript变量设置为可以在提交时监视的内容。

在与字段进行交互之前,我尝试更改files [0]的值。这与onchange无关。

因此,change可以,至少可以达到我们想要的效果。出于明显的原因,文件字段是安全的,但是出于良好意图的开发人员的考虑而感到沮丧。

这不符合我的目的,但是您可能能够onclick加载警告提示(不是alert(),因为它会暂停页面处理),并在触发更改且files [0]为null时将其隐藏。如果未触发更改,则div保持其状态。


0

有一种方法可以做到这一点(添加回调或解决某些延迟/承诺实现而不是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);

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

当然,但这不是检测已取消对话框的可靠方法。不过,可能会为您改善一些UI行为。


一个主要的缺点是在手机和平​​板电脑上,它们通常不使用鼠标!
彼得

0

这是我的解决方案,使用文件输入焦点(不使用任何计时器)

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) {
    // ...
}


运行您的Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
摘要

0

这充其量是很棘手的,但这是我的解决方案的一个有效示例,用于检测用户是否已上传文件,并且仅允许他们在已上传文件的情况下继续操作。

基本上隐藏ContinueSaveProceed或者无论你的按钮。然后在JavaScript中获取文件名。如果文件名没有值,则不显示Continue按钮。如果确实有值,则显示按钮。如果他们首先上传文件,然后尝试上传其他文件,然后单击“取消”,这也可以使用。

这是代码。

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来说,很多目的是使每个人都可以访问网站和按钮。将按钮样式设置为任意样式。


0

好吧,这并不能完全回答您的问题。我的假设是,您有一个场景,当您添加文件输入并调用文件选择时,如果用户单击“取消”,则只需删除输入。

如果是这种情况,那么:为什么要添加空文件输入?

即时创建一个,但仅在填写后将其添加到DOM。就像这样:

    var fileInput = $("<input type='file' name='files' style='display: none' />");
    fileInput.bind("change", function() {
        if (fileInput.val() !== null) {
            // if has value add it to DOM
            $("#files").append(fileInput);
        }
    }).click();

因此,我在此处动态创建<input type =“ file” />,绑定到它的change事件,然后立即调用click。仅当用户选择一个文件并单击“确定”时才会触发on change,否则输入将不会添加到DOM,因此不会提交。

这里的工作示例:https : //jsfiddle.net/69g0Lxno/3/


0

//使用悬停而不是模糊

var fileInput = $("#fileInput");

if (fileInput.is(":hover") { 

    //open
} else {

}

0

如果您已经需要JQuery,则此解决方案可能会起作用(这与我实际需要的代码完全相同,尽管使用Promise只是强制代码等待文件选择解决):

await new Promise(resolve => {
    const input = $("<input type='file'/>");
    input.on('change', function() {
        resolve($(this).val());
    });
    $('body').one('focus', '*', e => {
        resolve(null);
        e.stopPropagation();
    });
    input.click();

});


0

此线程中有几种建议的解决方案,这种难以检测用户单击文件选择框上的“取消”按钮的问题是影响很多人的问题。

事实是,没有100%可靠的方法来检测用户是否单击了文件选择框上的“取消”按钮。但是,有一些方法可以可靠地检测用户是否已将文件添加到输入文件中。所以这是这个答案的基本策略!

我之所以决定添加此答案,是因为其他答案显然不适用于大多数浏览器或无法在移动设备上使用。

简而言之,代码基于三点:

  1. 输入文件最初是在js的“内存”中动态创建的(目前我们不将其添加到“ HTML”中);
  2. 添加文件后,将输入文件添加到HTML,否则什么也没有发生。
  3. 通过特定事件从HTML删除输入文件来完成文件的删除,这意味着文件的“编辑” /“修改”是通过删除旧的输入文件并创建一个新的输入文件来完成的。

为了更好地理解,请查看下面的代码以及说明。

[...]
<button type="button" onclick="addIptFl();">ADD INPUT FILE!</button>
<span id="ipt_fl_parent"></span>
[...]
function dynIptFl(jqElInst, funcsObj) {
    if (typeof funcsObj === "undefined" || funcsObj === "") {
        funcsObj = {};
    }
    if (funcsObj.hasOwnProperty("before")) {
        if (!funcsObj["before"].hasOwnProperty("args")) {
            funcsObj["before"]["args"] = [];
        }
        funcsObj["before"]["func"].apply(this, funcsObj["before"]["args"]);
    }
    var jqElInstFl = jqElInst.find("input[type=file]");

    // NOTE: Open the file selection box via js. By Questor
    jqElInstFl.trigger("click");

    // NOTE: This event is triggered if the user selects a file. By Questor
    jqElInstFl.on("change", {funcsObj: funcsObj}, function(e) {

        // NOTE: With the strategy below we avoid problems with other unwanted events
        // that may be associated with the DOM element. By Questor
        e.preventDefault();

        var funcsObj = e.data.funcsObj;
        if (funcsObj.hasOwnProperty("after")) {
            if (!funcsObj["after"].hasOwnProperty("args")) {
                funcsObj["after"]["args"] = [];
            }
            funcsObj["after"]["func"].apply(this, funcsObj["after"]["args"]);
        }
    });

}

function remIptFl() {

    // NOTE: Remove the input file. By Questor
    $("#ipt_fl_parent").empty();

}

function addIptFl() {

    function addBefore(someArgs0, someArgs1) {
    // NOTE: All the logic here happens just before the file selection box opens.
    // By Questor

        // SOME CODE HERE!

    }

    function addAfter(someArgs0, someArgs1) {
    // NOTE: All the logic here happens only if the user adds a file. By Questor

        // SOME CODE HERE!

        $("#ipt_fl_parent").prepend(jqElInst);

    }

    // NOTE: The input file is hidden as all manipulation must be done via js.
    // By Questor
    var jqElInst = $('\
<span>\
    <button type="button" onclick="remIptFl();">REMOVE INPUT FILE!</button>\
    <input type="file" name="input_fl_nm" style="display: block;">\
</span>\
');

    var funcsObj = {
        before: {
            func: addBefore,
            args: [someArgs0, someArgs1]
        },
        after: {
            func: addAfter,

            // NOTE: The instance with the input file ("jqElInst") could be passed
            // here instead of using the context of the "addIptFl()" function. That
            // way "addBefore()" and "addAfter()" will not need to be inside "addIptFl()",
            // for example. By Questor
            args: [someArgs0, someArgs1]

        }
    };
    dynIptFl(jqElInst, funcsObj);

}

谢谢!= D


0

我们实现了如下所示的角度。

    1. 在输入类型文件上绑定单击事件。
      1. 将焦点事件与窗口关联,如果uploadPanel为true,则添加条件,然后显示控制台。
      2. 单击输入类型文件时,布尔型uploadPanel值为true。和对话框出现。
      3. 当取消或按Esc按钮时,将出现对话框药房和控制台。

的HTML

 <input type="file" formControlName="FileUpload" click)="handleFileInput($event.target.files)" />
          />

TS

this.uploadPanel = false;
handleFileInput(files: FileList) {
    this.fileToUpload = files.item(0);
    console.log("ggg" + files);
    this.uploadPanel = true;
  }



@HostListener("window:focus", ["$event"])
  onFocus(event: FocusEvent): void {
    if (this.uploadPanel == true) {
        console.log("cancel clicked")
        this.addSlot
        .get("FileUpload")
        .setValidators([
          Validators.required,
          FileValidator.validate,
          requiredFileType("png")
        ]);
      this.addSlot.get("FileUpload").updateValueAndValidity();
    }
  }

0

只需在类型为文件的输入上添加“更改”侦听器即可。即

<input type="file" id="file_to_upload" name="file_to_upload" />

我已经使用了jQuery,显然每个人都可以使用valina JS(根据要求)。

$("#file_to_upload").change(function() {

            if (this.files.length) {

            alert('file choosen');

            } else {

            alert('file NOT choosen');

            }

    });

.change()如果用户在文件选择器上单击“取消”,则不会可靠地调用该函数。
本·惠勒

@benWheeler,我已经在chrome和firefox上进行了检查,并且可以正常使用,但未在其他浏览器上进行过测试。
Naveed Ali

0
    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>

仅代码答案被认为是低质量的:确保提供解释代码的作用以及如何解决问题。如果您可以在帖子中添加更多信息,它将对询问者和将来的读者都有帮助。请参阅解释完全基于代码的答案
Calos,

0

隐藏输入的文件选择解决方案

注意:此代码不会检测取消,它提供了一种方法,可以避免在人们尝试检测取消的常见情况下检测到取消的需要。

我在这里寻找隐藏输入的文件上传解决方案时,我相信这是寻找一种检测文件输入取消的方法的最常见原因(打开文件对话框->如果选择了文件,然后运行一些代码,否则什么也不做),这是我的解决方案:

var fileSelectorResolve;
var fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');

fileSelector.addEventListener('input', function(){
   fileSelectorResolve(this.files[0]);
   fileSelectorResolve = null;
   fileSelector.value = '';
});

function selectFile(){
   if(fileSelectorResolve){
      fileSelectorResolve();
      fileSelectorResolve = null;
   }
   return new Promise(function(resolve){
      fileSelectorResolve = resolve;
      fileSelector.dispatchEvent(new MouseEvent('click'));
   });
}

用法示例:

请注意,如果未选择任何文件,则第一行将仅返回一次,selectFile()或者再次调用(或者fileSelectorResolve()从其他地方调用)。

async function logFileName(){
   const file = await selectFile();
   if(!file) return;
   console.log(file.name);
}

另一个例子:

async function uploadFile(){
   const file = await selectFile();
   if(!file) return;

   // ... make an ajax call here to upload the file ...
}

在chrome 83.0中,当用户取消时,我没有收到输入事件的回调,也没有第二次尝试
Soylent Graham,

1
@SoylentGraham是的,因为此代码无法检测到取消,所以它提供了一种在人们试图检测到它的常见情况下避免检测到它的需要的方法。由于尚不清楚,因此将此评论添加到我的答案中。
土豆

我不好,我想我把您的答案误读为“它告诉您用户第二次尝试已取消”
Soylent Graham

-1

您可以在输入字段上进行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
    }
});

不知道为什么要拒​​绝投票-这就是我一直在寻找的东西。谢谢!🙂
user1274820
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.