如何检测 html 的 input file 控件在文件输入时,用户点击了“取消”

发现问题

前几天,在使用 input file 控件监听用户文件选择弹出框的取消动作时,出现了很大困难,input file 文件打开动作只有 onchange 事件才能触发,因此在 onchange 事件内对取消动作判定无效,因为此时 onchange 事件没有触发,所以函数内的代码也不会执行。html 页面代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>input file</title>
</head>
<body>
    <a href="javascript:fclick();">浏览</a><p></p>
    <input type="file">
    <script>
        document.querySelector('input').style.display = 'none';
        function fclick() {
            document.querySelector('p').innerHTML = "打开文件...";
            document.querySelector('input').click();
        }
        document.querySelector('input').onchange = function () {
            files = this.files[0];
            if (files) {
                console.log("打开文件", files.name)
            } else {
                console.log('取消');
            }
        }
    </script>
</body>
</html>

提出问题

上面代码存在两个问题:
1, 如果两次选择打开相同文件,则第二次打开不会执行。
2, 若在页面对话框中选择了取消,无法监听或绑定用户取消动作。
这都是 input files 设计带来的问题,因为 input.value 值未改变, onchange 事件不会被触发。

解决问题

解决第1个问题的思路,大部分浏览器为了安全限制 input.value 值不可修改,但是可以被置空。因此,onchange 文件打开任务完成后,将缓存 input.value 值置空,第二次打开相同的文件之前 input.value 值是空的,onchange 就会被触发。

document.querySelector(‘input’).value = “”; //有效
document.querySelector(‘input’).value = “data.xls”; //无效

解决第2个问题的思路,文件打开对话框弹出后,当前页面失去焦点,当文件选择对话框关闭(无论是确定还是取消),页面将重新获取焦点。可以绑定页面获取焦点事件,判定用户是否取消了文件选择。
需要注意的是,浏览器页面获取焦点事件早于 onchange 事件约20毫秒,需要页面绑定的事件滞后执行,使用 setTimeout 即可。

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <script src="jquery-3.6.0.min.js"></script>
  <title>input控件研究</title>
</head>
<body>
    <button>打开图片</button><br><img><input type="file">
  <script>
    var inpt = $('input').hide(), FLAG = 0;
    $("button").bind("click", function () {
      inpt.click();
      FLAG = 1;
    });
    inpt.change(function (e) {
      var files = e.target.files[0];
      if (files) {
        FLAG = 2;  //文件打开标志
        //reader 对象读取打开文件内容
        var reader = new FileReader();
        reader.readAsDataURL(files);
        reader.onload = function () {          
          $("img").attr({ "src": this.result, "height": "320px" });
          //若两次打开同一个文件,则change事件不会发生,故须清空
          inpt.val('');
        }
      }
    });
    $(window).focus(f => {
      setTimeout(e => {
        if (FLAG == 1) {
          FLAG = 0;
          console.log('取消');
        }
      }, 100);
    });
  </script>
</body>
</html>

至此,两个问题完美解决。
目前网上最流行的 fileinput 文件上传插件,在最新的 5.2.6 版本似乎也没解决这个问题,测试发现,当文件选择框被取消时,载入文件的 loadding 动画会一直转圈,无法准确监测到用户取消动作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yxp_xa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值