前端上传图片

5,686 阅读1分钟

这是我参与更文挑战的第11天,活动详情查看: 更文挑战

前言

这篇文章用来介绍如何使用 js 上传图片,介绍了两种方法,一种是使用 ajax,另一种是使用 axios。

其实下面的代码也适合上传文件,稍微修改一下上传的限制就可以了。如果你要上传的不是图片,上传的是其他类型的文件,这篇文章也是值得一看。

以下内容均假设引用了 jq。

准备

首先,要写上一个隐藏的 input,用来读取图片文件,再写上一个上传按钮。

<!-- 用于预览图片,可以不写 -->
<img class="img" src="">

<!-- 用于读取图片 -->
<input class="input-img" type="file" accept="image/*" style="display: none;">

<!-- 用于触发事件 -->
<button class="upload-btn">选择图片上传</button>

当上传按钮被触发时,触发隐藏的 input 点击事件。

$('.upload-btn').click(function () {
    $('.input-img').click()
})

ajax 方式

当隐藏的 input 被触发,电脑或手机就会弹出新窗口提示用户选择图片,用户选择好图片后,input 的 change 事件会被触发,这个时候我们就要监听 change 事件,在里面写好自己的业务逻辑。

注意:change 事件里面一定要检测 input 里的 file 是否有值,因为 input 里的 file 如果被清除,change 事件也会被触发。

$('.input-img').on('change', function () {
    var file = $('.input-img').get(0).files[0]
    if (!file || file.length == 0) {
      return
    }
    var fileName = file.name;
    var fileType = fileName.substr(fileName.lastIndexOf(".")).toUpperCase();
    if (fileType != ".GIF" && fileType != ".PNG" && fileType != ".JPG" && fileType != ".JPEG") {
      alert('请选择图片文件!') // 提示
      return
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      alert('上传图片大小不能超过 2MB!') // 提示
      $('.input-img').get(0).value = ''
      return
    }
    
    // 有时候,我们上传图片时,需要将图片先预览,那么我们可以将图片转化为 base64 并展示出来
    $('.img').attr('src', fileToBase64(file))
    
    var formdata = new FormData()
    formdata.append("file", file)
    
    $.ajax({
        url: '后端地址',
        method: 'post',
        data: formdata,
        processData:false, // 不需要数据序列化,因为传输的数据是 FormData 对象
        contentType:false, // 不需要带有 headers 的 content-type 字段,因为传递 FormData 对象就已经默认了 mutipart/form-data
        xhr: function () {
            var xhr = new XMLHttpRequest()
            xhr.upload.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    var progress = Math.round(e.loaded * 100 / e.total) + '%'
                    console.log('上传进度:', progress)
                } else {
                    console.log('无法计算上传进度')
                }
            })
            xhr.upload.addEventListener('load', function(e) {
                console.log('上传成功')
            })
            xhr.upload.addEventListener('error', function(e) {
                console.log('上传失败')
            })
            xhr.upload.addEventListener('abort', function(e) {
                console.log('用户取消上传/浏览器断开了连接')
            })
            return xhr
        }
    }).done(function (data) {
        console.log('后端返回的信息:' + data)
    }).fail(function (err) {
        console.log(err)
        alert('服务器异常')
    })
})
  
/**
  * 文件流转为 base64
  * @param {*} file 
  */
function fileToBase64(file) {
    var URL = window.URL || window.webkitURL;
    return URL.createObjectURL(file);
}  

axios 方式

把上面代码的 ajax 部分替换为 axios 即可

axios({
      url: "后端地址",
      method: "post",
      headers: {
        "Content-Type": "multipart/form-data"
      },
      data: formdata,
      withCredentials: false,
      onUploadProgress: function (e) {
          var progress = Math.round(e.loaded / e.total * 100) + '%'
          console.log('上传进度:', progress)
      }
}).then(res => {
      console.log('后端返回的数据:' + res)
      console.log('上传成功')
}).catch(err => {
      console.log('上传失败')
})

同时上传多张图片

如果需要同时上传多张图片,需要在隐藏的 input 添加 multiple,允许 input 同时读取多张图片。

<input class="input-img" type="file" accept="image/*" style="display: none;" multiple>

js 里的 change 事件需要稍微修改一下,之前只是读取第一个文件,现在读取 files 数组。

$('.input-img').on('change', function () {
      // 读取文件数组
      var files = $('.input-img').get(0).files
      if (!files || files.length == 0) {
        return
      }
      // 检查每个文件
      for (var file of files) {
            var fileName = file.name;
            var fileType = fileName.substr(fileName.lastIndexOf(".")).toUpperCase();
            if (fileType != ".GIF" && fileType != ".PNG" && fileType != ".JPG" && fileType != ".JPEG") {
              alert('请选择图片文件!') // 提示
              return
            }
            const isLt2M = file.size / 1024 / 1024 < 2;
            if (!isLt2M) {
              alert(上传图片大小不能超过 2MB!) // 提示
              $('.input-img').get(0).value = ''
              return
            }
      }
      ...
})

后面的接口请求,需要看后端接口是否支持多图片同时上传,如果不支持,那就每上传一张图片,就调用一次接口。