antdesign+vue+ts自定义上传文件customRequest,显示进度条onProgress,axios请求中断axios.CancelToken。

ant自定义上传文件customRequest

customRequest里面有一个data参数,data包含了对file文件上传状态的操作:例如:onSuccess、onProgress、onError等 和file文件。
改变文件上传状态:可以通过改变fileList里面file的status和respones。

踩坑:
1、在customRequest文件上传完成以后,会自动重新更新一下fileList文件。上传之前挂载在file文件上的参数会丢失。
解决:必要参数创建一个新的list存放参数。通过文件uid关联

2、 删除文件, @remove默认会删除文件
解决:需要自定义删除fileList的时候,需要在方法后面 return false

dom代码

  <a-upload-dragger
            v-model:file-list="fileList"
            :multiple="true"
            :max-count="10"
            :disabled="fileList?.length >= 10"
            :customRequest="customRequest"
            @remove="handleRemove"
            :progress="progress"
            accept=".onnx,.pth"
            width="248px"
          >
          </a-upload-dragger>
 const customRequest = async (data: { file: any; onProgress?: any; onSuccess?: any }) => {
    const { file, onProgress, onSuccess } = data
 }

ant自定义上传文件 显示进度条

axios请求配置onUploadProgress,通过loaded和total计算出进度,自定义上传的onProgress同步进度到ant组件

  const progress: UploadProps['progress'] = {
    strokeColor: {
      '0%': '#108ee9',
      '100%': '#87d068'
    },
    strokeWidth: 3,
    format: percent => `${parseFloat(percent!.toFixed(2))}%`,
    class: 'test'
  } // 上传进度条
   const customRequest = async (data: { file: any; onProgress?: any; onSuccess?: any }) => {
    const { file, onProgress, onSuccess } = data
         let config = {
          timeout: 120000, //设置超时时长
          onUploadProgress: (Progress: { loaded: number; total: number }) => {
            let percents = Math.round((Progress.loaded * 100) / Progress.total)
            // 更新进度条
            onProgress({ percent: percents }, file)
          }
        }
        let formData = new FormData()
        formData.append('file', file)
        http
          .upload(url, formData, config)
          .then(resTwo => {
          })
          .catch(() => {
          })
 }

取消上传文件 axios中断请求

axios定义一个CancelToken,生成一个token promise带到请求,当需要中断请求的时候调用这个promise

  const CancelToken = axios.CancelToken
  const source = CancelToken.source()
  let config = {
          timeout: 120000, //设置超时时长
          onUploadProgress: (Progress: { loaded: number; total: number }) => {
            let percents = Math.round((Progress.loaded * 100) / Progress.total)
            // 更新进度条
            onProgress({ percent: percents }, file)
          },
          cancelToken: source.token
        }
        let formData = new FormData()
        formData.append('file', file)
        http
          .upload(url, formData, config)
          .then(resTwo => {
            onSuccess(resTwo, file)
          })
          .catch(() => {
            currenFile.status = 'error'
            currenFile.response = '上传失败'
          })
// 中断请求:
source.cancel('中断上传描述 可自定义。')

axios上传文件请求封装

 import Axios, from 'axios'
 export const http ={
  upload: (url: string, formData?: object, config?: object) => {
    return Axios({
      url: url, // 接口地址
      method: 'put',
      data: formData,
      ...config
    })
  }
 }

完整自定义上传代码

因为我是多文件上传,会涉及多个文件同时上传、取消中断。所以我定义了一个fileTokenArr存放文件上传的token

  import { http } from '@/services/http'
  
  interface File extends UploadFile {
    id?: string // 预上传后的id
  }
  const fileList = ref<File[]>([]) // 上传文件
  // 上传进度条
  const progress: UploadProps['progress'] = {
    strokeColor: {
      '0%': '#108ee9',
      '100%': '#87d068'
    },
    strokeWidth: 3,
    format: percent => `${parseFloat(percent!.toFixed(2))}%`,
    class: 'test'
  } 
  let fileTokenArr: FileToken[] = [] // 根据上传文件创建token数组
  
  const customRequest = async (data: { file: any; onProgress?: any; onSuccess?: any }) => {
    const { file, onProgress, onSuccess } = data

    // 在fileList获取当前文件
    const fileNameList = fileList.value.map(it => it.name)
    const fileIndex = fileNameList.lastIndexOf(file.name)
    let currenFile = fileList.value[fileIndex]

    // 判断同名文件
    const newFileList = fileList.value.slice()
    newFileList.splice(fileIndex, 1)
    let index = newFileList.findIndex(item => item.name === file.name)
    if (index !== -1) {
      message.error('暂不支持上传同名文件')
      currenFile.status = 'error'
      currenFile.response = '暂不支持上传同名文件'
      return false
    }

    // 判断文件类型
    let type = data.file.name.substr(data.file.name.lastIndexOf('.') + 1)
    if (type !== 'onnx' && type !== 'pth') {
      message.error('请上传onnx、pth格式的文件')
      currenFile.status = 'error'
      currenFile.response = '请上传onnx、pth格式的文件'
      return false
    }

    // 请求获取文件预上传地址和文件id
    let res = await req..............

    if (res) {
      if (res.code === 'SYSTEM-100000') {
        // axios token 用于中断请求
        const CancelToken = axios.CancelToken
        const source = CancelToken.source()
        // 存入token数组,uid为文件唯一标识。存入id是为了在正在上传的时候,取消预上传使用
        fileTokenArr.push({
          uid: file.uid,
          id: res.data[0].id,
          success: false,
          token: source
        })
        let uidFileIndex = fileTokenArr.findIndex(item => item.uid === currenFile.uid)

        // 根据上传地址上传问及那
        let config = {
          timeout: 120000, //设置超时时长
          onUploadProgress: (Progress: { loaded: number; total: number }) => {
            let percents = Math.round((Progress.loaded * 100) / Progress.total)
            // 更新进度条
            onProgress({ percent: percents }, file)
          },
          cancelToken: source.token
        }
        let formData = new FormData()
        formData.append('file', file)
        http
          .upload(res.data[0].presignedUrl, formData, config)
          .then(resTwo => {
            onSuccess(resTwo, file)
            // 上传成功以后: fileList被重新赋值,不能用currenFile
            const fileNameList = fileList.value.map(it => it.name)
            const fileIndex = fileNameList.lastIndexOf(file.name)
            fileList.value[fileIndex].id = res.data[0].id
            // 修改token数组里的上传状态
            fileTokenArr[uidFileIndex].success = true
            console.log('success', currenFile, fileList.value, fileTokenArr)
          })
          .catch(() => {
            currenFile.status = 'error'
            currenFile.response = '上传失败'
          })
      } else {
        message.error(res.message)
        currenFile.status = 'error'
        currenFile.response = res.message
        return false
      }
    }
  }
  // 删除单个预上传文件
  const handleRemove: UploadProps['onRemove'] = async (file: File) => {

    /**
     * 查询删除文件是否在正在上传文件数组
     * Y:(上传成功:调用取消预上传接口),(正在上传:调用axios中断上传请求,并调用取消预上传接口)
     * N: 从fileList移除该文件
     */
    let uidFileTokenIndex = fileTokenArr.findIndex(item => item.uid === file.uid)
    // 通过前端校验-已调用预上传接口
    if (uidFileTokenIndex !== -1) {
      // 未上传完成,正在上传
      if (!fileTokenArr[uidFileTokenIndex].success && file.status === 'uploading') {
        // 中断上传请求
        fileTokenArr[uidFileTokenIndex].token.cancel('中断上传。')
        // 移除文件操作
        ············
      } else {
        // 已上传完成-调用取消预上传接口
         // 移除文件操作
        ············
      }
    } else {
      // 前端判断失败的文件  (没有走预上传)
      const index = fileList.value.indexOf(file)
      const newFileList = fileList.value.slice()
      newFileList.splice(index, 1)
      fileList.value = newFileList
      return
    }
    return false
  }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用 Vite + Vue3 + TypeScript + Pinia + Vue Router + Axios + SCSS 并自动导入 API 的设置,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了 Node.js,并且版本大于等于 12.0.0。 2. 创建一个新的 Vue 项目,可以使用 Vue CLI 或者手动创建一个空文件夹。 3. 在项目根目录下,打开终端并执行以下命令安装 Vite: ```bash npm init vite@latest ``` 按照提示选择你的项目配置,包括选择 Vue 3、TypeScript 和其他选项。 4. 进入项目目录并安装依赖: ```bash cd your-project-name npm install ``` 5. 安装 Pinia 插件: ```bash npm install pinia ``` 6. 创建一个 `src/store` 目录,并在其中创建 `index.ts` 文件,用于定义和导出你的 Pinia store。 ```typescript // src/store/index.ts import { createPinia } from 'pinia' export const store = createPinia() // 可以在这里定义你的 store 模块 ``` 7. 在项目根目录下创建 `src/api` 目录,用于存放 API 请求相关的文件。 8. 在 `src/api` 目录下创建一个 `index.ts` 文件,用于自动导入所有 API 文件。 ```typescript // src/api/index.ts const modules = import.meta.globEager('./*.ts') const apis: any = {} for (const path in modules) { if (path !== './index.ts') { const moduleName = path.replace(/^.\/|\.ts$/g, '') apis[moduleName] = modules[path].default } } export default apis ``` 这样,你就可以在 `src/api` 目录下创建各种 API 请求的文件,例如 `user.ts`: ```typescript // src/api/user.ts import axios from 'axios' export function getUser(id: number) { return axios.get(`/api/user/${id}`) } ``` 然后,在你的组件中使用自动导入的 API: ```typescript import { defineComponent, ref } from 'vue' import { useUserStore } from '@/store' import apis from '@/api' export default defineComponent({ setup() { const userStore = useUserStore() const userId = ref(1) const fetchUser = async () => { const response = await apis.user.getUser(userId.value) userStore.setUser(response.data) } return { userId, fetchUser, } }, }) ``` 以上就是使用 Vite + Vue3 + TypeScript + Pinia + Vue Router + Axios + SCSS 并自动导入 API 的基本设置。你可以根据自己的需求进一步配置和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值