You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

点击按钮触发文件输入框后无法上传图片的问题求助

点击按钮触发文件输入框后无法上传图片的问题求助

我肯定是有个简单的点没搞明白,但就是找不到问题所在。

我用按钮(#clickme)触发文件输入框(#image-input)打开文件选择对话框,这么做是为了自定义按钮样式,这部分是有效的。但因为我在change事件里做了文件转换和创建新FormData对象的操作,结果图片没法上传了——只有直接点击文件输入框(#image-input)的时候才能正常上传。

我到底漏了什么?怎么才能既用按钮打开选择框,又能通过AJAX正常上传文件呢?我没有收到任何错误提示,就是文件没传上去。我怀疑change事件根本没触发?

我的代码如下:

$("#clickme").on("click", function () {
  $("#image-input").trigger("click");
});

$("#image-input").on("change", function (ev) {
  var originalFile = ev.target.files[0];

  if (
    originalFile.type === "image/heic" ||
    originalFile.name.toLowerCase().endsWith(".heic")
  ) {
    heic2any({
      blob: originalFile,
      toType: "image/jpeg",
    })
      .then(function (resultBlob) {
        var convertedFile = new File(
          [resultBlob],
          originalFile.name.replace(/\.heic$/i, ".jpg"),
          { type: "image/jpeg" },
        );

        var formData = new FormData();

        formData.append("image-input", convertedFile, convertedFile.name);

        // formData.append('otherField', 'value');

        uploadFile(formData);
      })
      .catch(function (x) {
        var error = "Error code: " + x.code + " " + x.message;
        console.log(error);
      });
  } else {
    var formData = new FormData();
    formData.append("image-input", originalFile, originalFile.name);
    uploadFile(formData);
  }
});

function uploadFile(formData) {
  $.ajax({
    url: base_url + "home/upload",
    type: "POST",
    data: formData,
    dataType: "json",
    mimeType: "multipart/form-data",
    contentType: false,
    cache: false,
    processData: false,
    success: function (response) {
      console.log(response);
    },
    error: function (error) {
      console.log(error);
    },
  });
}

问题分析与修复方案

首先,你怀疑change事件没触发其实大概率不是核心问题,不过有几个常见的坑会导致你遇到的情况:

  1. 重复选择同一文件时change事件不触发:文件输入框的change事件只有在value变化时才会触发,如果用户上次选了test.jpg,这次又选同一个文件,value没改,事件就不会跑。
  2. 事件绑定时机不对:如果你的代码在DOM还没加载完就执行了,那#image-input的事件绑定根本没挂上。
  3. AJAX请求的头设置冗余:手动加mimeType: "multipart/form-data"可能会和contentType: false冲突,jQuery会自动处理这个头。

下面是修复后的代码,我帮你补上了这些细节:

$(document).ready(function() {
  $("#clickme").on("click", function () {
    // 先重置输入框的value,确保重复选同文件也能触发change
    $("#image-input").val("");
    $("#image-input").trigger("click");
  });

  $("#image-input").on("change", function (ev) {
    var originalFile = ev.target.files[0];
    // 防止用户打开选择框后取消选择,避免后续报错
    if (!originalFile) return;

    if (
      originalFile.type === "image/heic" ||
      originalFile.name.toLowerCase().endsWith(".heic")
    ) {
      heic2any({
        blob: originalFile,
        toType: "image/jpeg",
      })
        .then(function (resultBlob) {
          var convertedFile = new File(
            [resultBlob],
            originalFile.name.replace(/\.heic$/i, ".jpg"),
            { type: "image/jpeg" },
          );

          var formData = new FormData();
          formData.append("image-input", convertedFile, convertedFile.name);

          uploadFile(formData);
        })
        .catch(function (x) {
          var error = "Error code: " + x.code + " " + x.message;
          console.log(error);
        });
    } else {
      var formData = new FormData();
      formData.append("image-input", originalFile, originalFile.name);
      uploadFile(formData);
    }
  });

  function uploadFile(formData) {
    $.ajax({
      url: base_url + "home/upload",
      type: "POST",
      data: formData,
      dataType: "json",
      contentType: false,
      cache: false,
      processData: false,
      success: function (response) {
        console.log(response);
      },
      error: function (error) {
        console.log(error);
      },
    });
  }
});

关键修复点说明:

  • 把所有代码放在$(document).ready()里,确保DOM元素加载完成后再绑定事件,避免找不到元素的问题。
  • 触发文件输入框点击前先执行$("#image-input").val(""),重置输入框状态,解决重复选同文件不触发change的问题。
  • 增加if (!originalFile) return;的判断,处理用户打开选择框后取消选择的情况,避免后续代码报错。
  • 移除了mimeType: "multipart/form-data",因为当contentType: false时,jQuery会自动正确设置请求头,手动设置反而可能导致格式错误。

另外,也可以检查一下后端接收文件的字段名是不是和你formData.append里的"image-input"完全一致,要是字段名不匹配,后端也拿不到文件哦。

备注:内容来源于stack exchange,提问作者opcode-devops

火山引擎 最新活动