element+vue模仿阿里云文件上传

偶然在抖音看到一个视频,渡一前端教育,看到了模仿阿里云文件上传,他讲解的是原生js实现,但是element有现成的插件,就想着自己做一个,然后 做了一个简单的demo,基于element+vue2.0实现的文件上传,我就实现了上传列表展示、上传实时监控、取消上传、上传统计等一些功能,后端本来做了指定文件限流、暂停上传、大文件分片上传一些操作,但是代码太多,前后端还有些bug,最近国庆节前工作有点忙,暂时没时间处理,就简化了,这里后端文件上传就提供一个简单的demo,在这里源码就免费奉献给大家,废话不多说,直接上代码。(ps:本人主做后端的,前端只是带着做,前端大佬不喜勿喷)

效果图

88decefd8f2077b357180fc94d139ff.png

前端

前端主要使用element的upload实现,el-upload有很多现成的方法直接调用,包括拖拽一些功能都是自带的,这里实现文件上传监控的方法也是其中之一,就是handleProgress,根据上传返回的已上传字节和总字节来计算上传率,watch实时监控fileList的变化,上传成功、上传时、上传失败、取消都会监控到。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>文件上传</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="../css/element.css">
    <script src="../js/vue.js"></script>
    <script src="../js/element.js"></script>
    <script src="../js/jquery-1.11.0.js"></script>
</head>
<body>
<div id="app">
    <el-upload
            class="upload-demo"
            drag
            ref="uploadRef"
            action="http://localhost:8686/file/upload"
            :on-remove="handleRemove"
            :on-progress="handleProgress"
            :on-change="handleChange"
            :on-success="handleSuccess"
            :on-error="handleError"
            :file-list="fileList"
            :auto-upload="false"
            :show-file-list="true"
            multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__text" style="margin-top: 10px">支持的文件类型:jpg、png、xml、word、pdf等,单个文件不超过1GB
        </div>
    </el-upload>
    <div class="uploadBtn">
        <el-button size="small" type="primary" @click="selectFile">选取文件</el-button>
        <el-button style="margin-left: 10px;" size="small" type="primary" @click="submitUpload">上传到服务器</el-button>
    </div>
    <div class="uploadTable">
        <el-tag>文件数量:{{fileTableData.length}}个</el-tag>
        <el-tag type="info">总大小:{{fileSizeSum}}M</el-tag>
        <el-tag type="success">成功上传:{{fileSuccessCount}}个</el-tag>
        <el-button type="danger" size="small" style="float: right" @click="clearTableData">清空上传列表</el-button>
        <el-table ref="fileTableData" :data="fileTableData" :cell-style="{textAlign:'center'}" stripe>
            <el-table-column prop="name" label="文件名"></el-table-column>
            <el-table-column prop="type" label="类型" width="80"></el-table-column>
            <el-table-column prop="sizeStr" label="大小"></el-table-column>
            <el-table-column prop="status" label="状态" width="120">
                <template slot-scope="scope">
                    <el-tag v-if="scope.row.status=='ready'" size="mini">待上传</el-tag>
                    <el-tag type="warning" v-else-if="scope.row.status==='uploading'" size="mini">上传中</el-tag>
                    <el-tag type="danger" v-else-if="scope.row.status==='fail'" size="mini">上传失败</el-tag>
                    <el-tag type="success" v-else-if="scope.row.status==='success'" size="mini">上传成功</el-tag>
                </template>
            </el-table-column>
            <el-table-column label="进度" width="120">
                <template slot-scope="scope">
                    <el-progress :text-inside="true" :stroke-width="15" :percentage="scope.row.num"></el-progress>
                </template>
            </el-table-column>
            <el-table-column label="操作">
                <template slot-scope="scope">
                    <el-button type="danger" class="el-icon-close" size="mini"
                               :disabled="!(scope.row.status==='uploading')"
                               @click="cancelUpload(scope.$index,scope.row)" title="取消上传"></el-button>
                    <el-button type="danger" class="el-icon-delete" size="mini"
                               @click="delFile(scope.$index,scope.row)" title="删除文件"></el-button>
                </template>
            </el-table-column>
        </el-table>
    </div>
</div>
</body>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                fileList: [],
                fileTableData: [],
                fileSizeSum: 0,
                fileSuccessCount: 0,
            }
        },
        watch: {
            fileList(newList) {
                this.fileTableData = [];
                let fileSizeSum = 0;
                newList.forEach(item => {
                    let row = $.extend(true, {}, item);
                    row.type = item.name.substring(item.name.lastIndexOf("."), item.name.length);
                    row.sizeStr = Math.round(item.size / 1024) + 'KB';
                    this.fileTableData.push(row);
                    fileSizeSum += item.size;
                })
                this.fileSizeSum = Math.round(fileSizeSum / (1024 * 1024) * 100) / 100;
            }
        },
        methods: {

            /**
             * 提交上传
             */
            submitUpload() {
                if (this.fileList.length <= 0) {
                    this.$message.warning("文件上传列表为空,请选择唔要上传的文件");
                    return;
                }
                this.$refs.uploadRef.submit();
            },
            
            handleChange(file, fileList) {
                this.fileList = fileList;
            },
           
            handleRemove(file, fileList) {
                this.fileList = fileList;
            },

           
            handleProgress(event, file, fileList) {
                fileList.forEach(item => {
                    if (file.uid === item.uid) {
                        if (item.status != 'success' || item.status != 'fail') {
                            let num = ((event.loaded / event.total) * 100) | 0; //重新计算上传百分比
                            item.num = num;
                            if (num == 100) {
                                this.fileSuccessCount++;
                            }
                        }
                    }
                })
                this.fileList = fileList;
            },

            handleSuccess(response, file, fileList) {
                this.fileList = fileList;
            },
          
            handleError(err, file, fileList) {
                this.$message.error("服务器连接失败,请检查网络重新上传");
            },

            
            selectFile() {
                const fileInput = this.$refs.uploadRef.$el.querySelector('input[type=file]');
                fileInput.click();
            },
           
            clearTableData(fileList) {
                this.fileList = [];
                this.fileTableData = [];
                this.fileSizeSum = 0;
                this.fileSuccessCount = 0;
            },
           
            cancelUpload(index, row) {
                let afterFileList = this.fileList;
                if (row.status === 'uploading') {
                    console.info("取消上传:" + row.name);
                    this.$refs.uploadRef.abort(row.raw);
                    afterFileList.forEach(item => {
                        if (item.uid === row.uid) {
                            item.status = 'ready';
                            //item.num = 0;//进度条归零
                        }
                    })
                }
                this.fileList = afterFileList;
                this.setTableData(this.fileList);
            },

            
            delFile(index, row) {
                this.fileList.splice(index, 1);
            },

            
            setTableData(newList) {
                this.fileTableData = [];
                let fileSizeSum = 0;
                newList.forEach(item => {
                    let row = $.extend(true, {}, item);
                    row.type = item.name.substring(item.name.lastIndexOf("."), item.name.length);
                    row.sizeStr = Math.round(item.size / 1024) + 'KB';
                    this.fileTableData.push(row);
                    fileSizeSum += item.size;
                })
                this.fileSizeSum = Math.round(fileSizeSum / (1024 * 1024) * 100) / 100;
            },
        }
    });
</script>
<style>
    .el-upload {
        display: contents;
    }

    .el-upload-dragger {
        width: 60%;
        margin: auto;
    }

    .el-upload-list {
        width: 60%;
        margin: auto;
    }

    .uploadBtn {
        width: 60%;
        margin: 20px auto;
    }

    .uploadTable {
        width: 60%;
        margin: auto;
    }

    table th .cell {
        color: #606266;
        text-align: center;
        font-size: 13px;
    }


    .el-badge__content.is-fixed.is-dot {
        right: 5px;
    }
    .el-badge__content.is-dot {
        height: 8px;
        width: 8px;
        padding: 0;
        right: 0;
        border-radius: 50%;
    }
    .el-badge__content.is-fixed {
        position: absolute;
        top: 0;
        right: 10px;
        transform: translateY(-50%) translateX(100%);
    }
    .el-badge__content {
        background-color: #f56c6c;
        border-radius: 10px;
        color: #fff;
        display: inline-block;
        font-size: 12px;
        height: 18px;
        line-height: 18px;
        padding: 0 6px;
        text-align: center;
        white-space: nowrap;
        border: 1px solid #fff;
    }
</style>
</html>

后端

后端代码就很简单了,就不多赘述,做了一个批量上传文件,稍微懂一点java的都可以看懂

@RestController
@RequestMapping("file")
public class UploadController {

    @ApiOperation("文件上传")
    @PostMapping("/upload")
    @ResponseBody
    public Object upload(HttpServletRequest request) {
        Map<String, String> resultMap = new HashMap<>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        if (multipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            //取得request中的所有文件名
            Iterator<String> iter = multiRequest.getFileNames();
            while (iter.hasNext()) {
                  //获取文件流
                MultipartFile uploadFile = multiRequest.getFile(iter.next());
                //获取文件名
                String beforeName = uploadFile.getOriginalFilename();//原始文件名
                String realPath = "C:/文件上传测试/upload1";

                File uploadDir = new File(realPath);
                //不存在文件夹则创建
                if (!uploadDir.exists()) {
                    uploadDir.mkdir();
                }
                String uuid = UUID.randomUUID().toString();
                String afterName = uuid + "_" + beforeName;
                try {
                    uploadFile.transferTo(new File(uploadDir, afterName));
                } catch (IOException e) {
                    e.printStackTrace();
                    return "上传失败";
                }
                resultMap.put("fileId", uuid);
                resultMap.put("fileName", afterName);
                return resultMap;
            }
        }
        return "上传失败";
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itfound_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值