阅读 233

element-ui上传列表自定义实现,上传错误重传等公共组件

为什么需要自定义实现

当然是原生的element-ui不满足

  • 展示的列表,elementui里面的请求错误的,不会展示在列表里面

  • element判断上传成功和失败是通过最外层的服务端返回的状态,而对于我们公司的后端,不论是成功还是失败都是返回的200,在返回值里面在封装了一层code来反应真正的成功或者失败,200表示成功,-1表示失败

image.png image.png

实现的功能

  • 会标明哪些上传成功和哪些是上传失败的

  • 上传失败的可以重新上传

  • 上传失败有错误提示,相同的错误提示只会提示一次

  • 可以调节一排显示的个数

由于时间比较紧张,代码可能有一点乱,后期有时间在优化 其中用到的前端后端代码都有 1.gif

后端代码

这里你可以随意返回,我是根据公司这边需求来做的 启动服务

node ./app.js  复制代码

// app.js const express = require('express') const app = express() const path = require('path') //引入multer const multer = require('multer') //注册一个对象,dest里放的是上传的文件存储的位置,可以在当前目录下,建立一个static目录,上传的文件都放在这里 const upload = multer({dest: './static/'}) //使用中间件,没有挂载路径,应用的每个请求都会执行该中间件。any表示接受一切,具体参考文档。 app.use(upload.any()) let errorNum = 0 //在req.files中获取文件数据 app.post('/api/upload',function(req, res){   const { originalname } = req.files[0]   console.log(originalname, req.files)   if (path.extname(originalname) === '.pdf') {     res.send({       code: '-1',       message: '上傳格式不能是txt和pdf'     })   }   else if(path.extname(originalname) === '.txt' && errorNum < 5) {     errorNum++     res.status(500).send({       code: '500',       message: '上传失败'     })   } else {     res.send({       code: '200',       message: '成功'     })   } }) app.listen(3000) 复制代码

前端组件的封装

// CommonUpload/index.vue <template>   <div>     <el-upload       :show-file-list="false"       :on-success="handleSuccess"       v-bind="$attrs"       v-on="$listeners"       :on-progress="handleProgress"       :on-error="handleError"       ref="upload-outer"     >       <slot>         <el-button size="small" type="primary">点击上传</el-button>       </slot>     </el-upload>     <UploadList       :file-list="fileList"       @refreshUpload="refreshUpload"       @handleDelete="handleDelete"     ></UploadList>   </div> </template> <script> import UploadList from '@/components/CommonUpload/UploadList'; export default {   name: 'CommonUpload',   components: {     UploadList   },   props: {     attachList: {       type: Array,       default: () => []     }   },   data() {     return {       fileList: [],       errTipsMap: {},       refreshUploadFileInfo: { // 主要是为了上传失败,上传失败过后位置会发生变化         file: '',         index: 0,         progressing: false // 是否在重新上传       }     }   },   watch: {     attachList: {       handler(newVal) {         this.fileList = newVal       },       immediate: true,       deep: true     },     fileList: {       handler(newVal) {         this.$emit('update:attachList', newVal)       },       immediate: true,       deep: true     }   },   methods: {     changeResponseStatus(fileList) {       fileList.forEach(item => {         if ((item.status !== 'success' || item.status !== 'fail') && item.response && item.response.code !== '200') {           item.status = 'fail'         }       })       return fileList     },     // 成功回调函数     handleSuccess(response, file, fileList) {       this.fileList = this.changeResponseStatus(fileList)       // 这里给出错误提示       const statusList = this.fileList.filter(item => ['success', 'fail'].includes(item.status) && item.response)       const isAllEnd = statusList.length === fileList.length       // 错误提示等全部上传完了,在给出提示,并且去除重复的提示       if (isAllEnd) {         const errFileList = this.fileList.filter(item => item.status === 'fail')         const errMessageList = []         errFileList.forEach(item => {           if (!this.errTipsMap[item.uid]) {             errMessageList.push(item.response.message)             this.errTipsMap[item.uid] = true           }         })         // 错误信息去重         const noRepeatMsgList = [...new Set(errMessageList)]         if (noRepeatMsgList.length) {           this.$message.error(noRepeatMsgList.join(','))         }       }     },     isRefreshUpload() {       if (this.refreshUploadFileInfo.progressing) {         return true       }     },     handleError(err, file, fileList) {       if (file.status !== 'fail') {         return       }       if (this.isRefreshUpload()) {         this.refreshUploadFileInfo.progressing = false         this.fileList.splice(this.refreshUploadFileInfo.index, 0, file)       } else {         this.fileList.push(file)       }       this.errTipsMap[file.uid] = true       this.$message.error(file.response?.message || '上传失败啦~~')     },     handleProgress(event, file, fileList) {       this.fileList = this.changeResponseStatus(fileList)     },     refreshUpload(file) {       this.errTipsMap[file.uid] = false       this.refreshUploadFileInfo = {         file: file,         index: this.fileList.findIndex(item => item.uid === file.uid),         progressing: true       }       this.$refs['upload-outer'].$refs['upload-inner'].upload(file.raw)     },     handleDelete(file) {       const delInd = this.fileList.findIndex(item => item.uid === file.uid)       this.fileList.splice(delInd, 1)     }   } } </script> <style scoped> </style> 复制代码

// CommonUpload/UploadList <template>   <div>     <div       v-for="file in fileList"       :key="file.uid"     >       <div>         <i class="el-icon-tickets file-prev-icon"></i>         <div :title="file.name" >           <span>{{ file.name }}</span>         </div>         <div>           <div>             <div v-if="file.status === 'uploading'">{{ parsePercentage(file.percentage) + '%' }}</div>             <div v-else-if="file.status === 'success'">               <i></i>             </div>             <div v-else-if="file.status === 'fail'">               <i></i>             </div>           </div>           <div>             <i v-if="file.status === 'fail'" @click="refreshUpload(file)"></i>             <i @click="handleDelete(file)"></i>           </div>         </div>       </div>       <el-progress         v-if="file.status === 'uploading'"         :type="'line'"         :stroke-width="2"         :percentage="parsePercentage(file.percentage)"         :show-text="false"       >       </el-progress>     </div>   </div> </template> <script> export default {   name: 'UploadList',   props: {     fileList: {       type: Array,       default: () => []     }   },   methods: {     parsePercentage(val) {       return parseInt(val, 10);     },     refreshUpload(file) {       this.$emit('refreshUpload', file)     },     handleDelete(file) {       this.$emit('handleDelete', file)     }   } } </script> <style scoped>   .upload-list__item {     height: 32px;     display: flex;     align-items: center;     position: relative;     font-size: 12px;     color: #2f2725;     overflow: hidden;   }   .upload-list__item-name {     display: flex;     align-items: center;     padding: 0 12px;     height: 100%;     width: 100%;   }   .file-after-icon, file-prev-icon, hover-delete {     flex-shrink: 0;   }   .after-icon-box {     width: 40px;     text-align: end;   }   .file-name {     flex: 1;     margin-right: 10px;     text-overflow: ellipsis;     white-space: nowrap;     overflow: hidden;   }   .file-prev-icon {     margin-right: 10px;   }   .progress-box {     position: absolute;     left: 0;     bottom: 0;     width: 100%;   }   .hover-delete {     display: none;     .el-icon-close {       color: #c1cfe0;       cursor: pointer;     }     .el-icon-refresh-right {       margin-right: 5px;       cursor: pointer;     }   }   .upload-list__item-name:hover {     background: #eff7ff;       .file-after-icon {         display: none;       }       .hover-delete {         display: block;       }   }   .file-after-icon {     font-size: 12px;     .el-icon-success {       color: #7cd4ab;     }     .el-icon-error {       color: #f66969;     }   }   .upload-list__container {     display: grid;     grid-template-columns: 1fr 1fr;     grid-column-gap: 20px;   } </style> 复制代码

测试代码

<template>   <div>     <div>jobTest</div>     <div style="width: 800px;">       <CommonUpload         action="/api/upload"         multiple         ref="upload-outer"         :attach-list.sync="attachList"       >       </CommonUpload>     </div>   </div> </template> <script> import CommonUpload from '@/components/CommonUpload' export default {   name: 'JobTest',   components: { CommonUpload },   data() {     return {       // 附件列表格式       attachList: [         // {         //   uid: 1000,         //   name: 'vueyuanma',         //   raw: 'file',         //   response: null,         //   status: 'success'         // },         // {         //   uid: 1001,         //   name: '哈哈',         //   raw: 'file',         //   response: null,         //   status: 'success'         // }       ]     }   },   methods: {} } </script> <style scoped> </style>


作者:Abby不想说话46050
链接:https://juejin.cn/post/7054181880521818142


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐