网络日志

antd-vue upload自定义下载文件

功能要求:上传文件后点击已上传的文件,实现图片格式与pdf格式的文件打开预览文档格式的文件点击下载并且下载时候的文件名与上传时保持一致。

问题:由于后台为了解决可能出现的相同文件名上传而导致后传的文件覆盖上一次文件的情况,就在文件上传至服务器后在文件名后面加一串随机串。这样导致在接口返回给前端的url的地址上会变成 文件名+随机字符串 。同时,这样就导致前端也出现一个情况:如果直接用a-upload组件封装的点击事件进行文件下载,下载后的文件名后会有一串随机字符串。这样就不符合需求要求的保证下载时的文件名称与上传一致,为此,就需要自定义一下a-upload的点击下载事件。

现象

出现原因:a-upload组件在上传了文件后,自动生成了a标签,点击文件时触发a标签的下载事件。如图

解决

<div class="divBox" v-for="(item, index) uploadList" :key="item.title">
  <span v-if="item.title" class="divBox-title">{{ item.title }}:</span>
  <a-upload
    v-model:file-list="item.fileList"
    :customRequest="customRequest"
    :beforeUpload="beforeUpload"
    :accept="item.accept"
    @preview="previewFile"
  >
    <a-button :loading="item.loading" :disabled="item.loading"> Upload </a-button>
  </a-upload>
</div>
const uploadList = ref([]) // 文件数组
const fIndex = ref() // 当前上传数据索引

// 上传
const customRequest = file => {
  const api = uploadList[fIndex.value].api
  const maxNum = uploadList[fIndex.value].maxNum
  const formData = new FormData()
  formData.append('file', file.file)
  //  去除后缀指定文件名
  formData.append('fileName', file.file.name.substring(0, file.file.name.lastIndexOf('.'))) 
  // 获取当前文件上传前文件数量
  const listNum = uploadList[fIndex.value].fileList.length
  request
    .post(url, formData)
    .then(res => {
      if (res.result == 0) {
        // 上传成功储存url
        uploadList[fIndex.value].fileList[uploadList[fIndex.value].fileList.length - 1].url = res.data.url
          const params = { url: res.data.url }
          request.post(api, params).then(result => {
          if (result.result == 0) {
            file.onSuccess(res, file.file)
            // 上传成功判断是否超出文件数量
            if (listNum >= maxNum) {
              // 超出文件数量删除第一项文件
              uploadList[fIndex.value].fileList.shift()
            }
          } else {
            message.error(result.message)
            uploadList[fIndex.value].fileList.splice(listNum, 1)
          }
          uploadList[fIndex.value].loading = false
        })
        .catch(() => {
          uploadList[fIndex.value].loading = false
        })
        .finally(() => {
          // 请求结束更改为结束状态
          uploadList[fIndex.value].loading = false
        })
      } else {
        uploadList[fIndex.value].fileList.splice(listNum, 1)
      }
    })
    .catch(() => {
      // 上传失败
      uploadList[fIndex.value].fileList.splice(listNum, 1)
    })
}

// 上传前事件
const beforeUpload = (file, fileList) => {
  const size = uploadList[fIndex.value].size
  const maxNum = uploadList[fIndex.value].maxNum
  const fileLists = uploadList[fIndex.value].fileList
  const isVerify = uploadList[fIndex.value].isVerify
  const accept = uploadList[fIndex.value].accept
  const isLt = file.size / 1024 / 1024 < size
  // 校验文件格式
  let type = false
  accept.split(',').forEach(e => {
    const filetype = file.name.split('.')[file.name.split('.').length - 1]
    if ('.' + filetype == e) {
      type = true
    }
  })
  if (!type) {
    message.error('文件格式错误,请重新上传')
    fileList.pop()
    return false
  } else {
    // 校验文件数量
    if (fileLists.length < maxNum) {
      // 校验文件大小
      if (!isLt) {
        message.error('文件大小超出' + size + 'M,请修改后重新选择文件')
        fileList.pop()
        return false
      } else {
        return true
      }
    } else {
      if (isVerify) {
        return true
      } else {
        message.error('上传数量不能超过' + maxNum + '个')
        fileList.pop()
        return false
      }
    }
  }
}

// 自定义的下载和预览方法
const previewFile = item => {
  // 根据文件的后缀进行预览或是下载操作
  if (item.name.endsWith('.jpg') || item.name.endsWith('.png')) {
    const imgWindow = window.open('')
    imgWindow && imgWindow.document.write(`<image src='${item.url}' style='display: flex; margin: 0 auto'/>`)
  } else if (item.name.endsWith('.pdf')) {
    window.open(item.url + '?response-content-type=application/pdf')
  } else {
    if (item.url) {
      downloadFile(item.url, item.name)
    }
  }
}

// 下载文件 将后台返回的文件url链接转换为文件流格式,点击打开新窗口下载文件
const downloadFile = async (url, fileName = null) => {
  const a = document.createElement('a') // 创建a标签
  if (fileName) {
    const response = await fetch(url) // 内容转变成blob地址
    const blob = await response.blob() // 创建隐藏的可下载链接
    const objectUrl = window.URL.createObjectURL(blob)
    a.href = objectUrl
    a.download = fileName
  } else {
    a.href = url
  }
  a.click()
  a.remove()
}

这样就可以将文件按照需求要求进行下载和预览