el-upload上传之自定义上传/关闭页面中断请求

上传组件:组件效果
el-upload上传之自定义上传/关闭页面中断请求_第1张图片
功能说明:

  1. 上传为post请求,请求需要携带四个参数,其中有file上传的文件

  2. 自定义上传时显示进度条,正在上传的文件删除要杀死当前这个请求,这里是用的file.uid进行的对号查找

  3. 当有任务上传时,关闭或者刷新页面要杀死所有请求。

组件代码:

<template>
  <div class="children_box">
    <div class="inner">
    <span v-if="title" class="subTitle">
    <el-tooltip
      :disabled="disabledFn(childData.data.directoryName)"
      :content="childData.data.directoryName"
      placement="top"
      effect="light"
    >
    <span> {{ getDirNameFn(childData.data.directoryName) }}</span>
    </el-tooltip>
    </span>
      <div class="opt" :style="getOptStyle()">
        <svg-icon icon-class="btn_shangchuan"></svg-icon>
        <span class="s" @click="uploadClickFn(childData.data.id)">上传文件</span>
      </div>
    </div>
    <div class="upload_box">
      <el-upload
        ref="fileRefs"
        class="upload-box"
        action="#"
        :http-request="UploadFn"
        :on-remove="handleRemove"
        :before-remove="beforeRemove"
        :before-upload="beforeUpload"
        :on-success="handleSuccess"
        :file-list="fileList"
      >
        <el-button v-if="false" size="small" type="primary">点击上传</el-button>
      </el-upload>
    </div>
  </div>
</template>
<script>
import axios from 'axios'
import { taskDetailUpload, taskDetailFileList, taskDetailFileDelete } from '@/views/testManage/TDUpload/constants/API'
import { getStringLength } from '@/utils/getStringLength'
export default {
  props: {
    childData: {
      required: true
    },
    needObj: {
      required: true,
      type: Object
    },
    title: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      fileList: [],
      //  上传接口
      taskDetailUpload,
      //   上传入参
      sendData: {
        projectId: this.needObj.projectId,
        taskId: this.needObj.taskId,
        directoryId: ''
      },
      // 存储当前要取消的请求
      source: [],
      // 存储请求的数组
      requestArr: [],
      //  上传成功标志
      isSuccess: true,
      // 是否在中断取消时候出现message提示框
      isShowCancel: false,
      // 上传文件是否符合规定大小,因为beforeUpload方法不符合大小会触发remove方法,所以做个判定,
      // 默认值为必须为true,为了回显文件列表的时候也能走beforeRomove删除逻辑
      fileSizeError: true
    }
  },
  watch: {
    isSuccess(val) {
      if (!val) {
        // 当还有正在上传的文件,此时关闭或刷新浏览器,杀死所有请求
        window.addEventListener('beforeunload', this.sureCloseWinowFn)
      }
    }
  },
  created() {
    this.getFilesListFn()
  },
  mounted() {},
  destroyed() {
    window.removeEventListener('beforeunload', this.sureCloseWinowFn)
  },
  methods: {
    sureCloseWinowFn(e) {
      e = e || window.event
      e.preventDefault()
      e.returnValue = ''
      this.isShowCancel = true
      this.requestArr.forEach(x => {
        x.cancel()
      })
    },
    // 回显上传列表
    getFilesListFn() {
      const params = {
        directoryId: this.childData.data.id,
        taskId: this.sendData.taskId
      }
      taskDetailFileList(params).then(res => {
        // console.log(res, '回显文件列表数据')
        // 回显已经上传的文件列表
        this.fileList = res.map(item => {
          return {
            name: item.fileName,
            fileId: item.fileId,
            directoryId: item.directoryId,
            id: item.id
          }
        })
      })
    },
    // 自定义上传方式
    UploadFn(params) {
      // console.log(params, '上传参数')
      const formData = new FormData()
      formData.append('file', params.file)
      formData.append('projectId', this.needObj.projectId)
      formData.append('taskId', this.needObj.taskId)
      formData.append('directoryId', this.childData.data.id)
      const CancelToken = axios.CancelToken
      const source = CancelToken.source()
      axios({
        method: 'post',
        url: taskDetailUpload,
        data: formData,
        cancelToken: source.token,
        onUploadProgress: progressEvent => {
          // axios自带api,获取上传进度
          const complete = parseInt(((progressEvent.loaded / progressEvent.total) * 100) | 0, 10)
          params.onProgress({ percent: complete }) // 调用组件自带进度条
          // 还没有上传成功标识
          this.isSuccess = false
        }
      })
        .then(res => {
          // 触发handleSuccess函数
          // 显示完成按钮小图标
          params.onSuccess({
            status: true,
            id: res.data.data
          })
        })
        .catch(err => {
          //   console.log(this.$refs.fileRefs.uploadFiles, '上传文件列表??')
          if (!this.isShowCancel) {
            this.$message.warning(err.message)
          }
          const uid = params.file.uid
          const idx = this.$refs.fileRefs.uploadFiles.findIndex(item => item.uid === uid) // 关键作用代码,去除文件列表失败文件(uploadFiles为el-upload中的ref值)
          if (idx > 0) {
            this.$refs.fileRefs.uploadFiles.splice(idx, 1) // 关键作用代码,去除文件列表失败文件
          }
        })
      // 存储一份uid,知道在删除的时候是杀死的哪个请求
      this.source.push({
        source: source,
        uid: params.file.uid
      })
      // 这个直接存储,为了关闭页面刷新页面全部杀死请求
      this.requestArr.push(source)
    },
    uploadClickFn(id) {
      this.sendData.directoryId = id
      this.$refs['fileRefs'].$refs['upload-inner'].handleClick()
    },
    handleSuccess(response, file, fileList) {
      console.log(response, '----', file, '====', fileList)
      this.isSuccess = response.status
      // this.getFilesListFn()//删除后及时显示在列表中,不用刷新回显列表
    },
    beforeUpload(file) {
      // 判断文件是否大于10G  10000
      const isSize = file.size / 1024 / 1024 < 10000
      if (!isSize) {
        this.$message.warning('文件不得大于10G')
        this.fileSizeError = false
      } else {
        this.fileSizeError = true
      }
      return isSize
    },
    handleRemove(file, fileList) {
      console.log(file, fileList)
    },
    beforeRemove(file) {
      // console.log(file, '当前文件')
      if (this.fileSizeError) {
        console.log(file)
        // alert(1223)
        return this.$confirm(`确定删除 ${file.name}`).then(() => {
          // 如果有id,说明是已经传上去的文件做删除,
          // file.response.id是在上传成功后我们自动装进去的后端返回的id,目的在于因为上传后不重新调回显接口(调了后我们对filelist做了渲染的组装数据),不调是因为万一有大文件在上传就会丢失当前上传列表,所以这里是file.response是我们自己组装的数据,目的在于我们删除一个刚上传的数据又做了删除操作。能取到我们组装好的id
          if (file.id || file.response.id) {
            // 删除接口
            taskDetailFileDelete({ id: file.id }).then(() => {
              this.$message.success('删除成功')
              // this.getFilesListFn() //删除后及时显示在列表中,不用刷新回显列表(防止还有别的大文件在上传)
            })
          } else {
            // 没上传完成点击删除就中断请求
            this.source.forEach(item => {
              if (item.uid === file.uid) {
                item.source.cancel('您已取消了请求') // 这里的提示会在axios的catch的error中捕获到
              }
            })
          }
        })
      }
    },
    getDirNameFn(val) {
      return getStringLength(val) <= 20 ? val : val.substr(0, 18) + '...'
    },
    // 判断节点的文字长度是否出现tool-tip
    disabledFn(attr) {
      if (!attr) return true
      if (getStringLength(attr) < 20) return true
    },
    getOptStyle() {
      return this.title ? { marginLeft: '26px' } : { marginLeft: 0 }
    }
  }
}
</script>
<style scoped lang="scss">
@mixin buttonStyle {
  padding-left: 16px;
  line-height: 28px;
  padding-right: 24px;
  border: 1px solid #fe992c;
  border-radius: 8px;
  color: #fe992c;
  text-align: center;
  cursor: pointer;
  svg {
    vertical-align: middle;
  }
  .s {
    font-size: 14px;
    padding-left: 5px;
    vertical-align: middle;
  }
}
.children_box {
  margin: 20px 40px 0 -20px;
  .inner {
    display: flex;
    align-items: center;
    .subTitle {
      color: rgba(191, 191, 191, 1);
    }
    .opt {
      width: 130px;
      height: 32px;
      @include buttonStyle;
    }
  }
  .upload_box {
    // height: 200px;
    // background: red;
    padding-bottom: 10px;
  }
  ::v-deep .el-upload-list__item-name [class^='el-icon'],
  ::v-deep .el-upload-list__item .el-icon-close-tip {
    color: rgba(250, 140, 22, 1);
  }
}
</style>

你可能感兴趣的:(vue记录,javascript,前端,vue.js)