vue-simple-uploader实现多文件/文件夹以及可拖拽上传
vue-simple-uploader实现多文件/文件夹以及可拖拽上传
·
vue-simple-uploader的简单使用
vue-simple-uploader是基于simple-uploader.js的vue上传组件
- 支持多文件/文件夹上传,拖拽上传
- 可暂停、继续上传
- 上传错误处理
- 支持“秒传”,通过文件判断服务端是否已存在从而实现“秒传”
- 支持进度、预估剩余时间、出错自动重试、重传等操作
1.效果图展示
后面有使用拖拽上传文件/文件夹
上传遇到同名的文件会有一个弹框提示,并有相关的操作
2.安装
npm install vue-simple-uploader --save
3.vue2使用(vue3使用会报错)
import uploader from 'vue-simple-uploader'
//已经创建Vue实例了
Vue.use(uploader)
4.代码
这里我只贴主要的内容,代码也都给有注释哦
<uploader
ref="uploader"
:options="options"
:auto-start="false"
:file-status-text="fileStatusText"
class="uploader-example"
@file-added="onFileAdded"
@files-added="onFilesAdded"
@file-error="onFileError"
@file-complete="onFileComplete"
>
<uploader-unsupport /> //不支持上传时显示内容
//这个组件也有两个上传的按钮 但是我这边给隐藏了 自定义了下拉框 点击的时候 获取对应的实例 然后触发点击事件
<uploader-btn
id="uploader_btn"
ref="uploadBtn"
>选择文件</uploader-btn>
<uploader-btn
id="uploader_btn"
ref="uploadFolderBtn"
:directory="true"
>选择文件夹</uploader-btn>
//可拖拽的区域
<uploader-drop class="drop">
//我把这个table区域变成可拖拽的了 具体看自己写的内容吧
<el-table></el-table>
</uploader-drop>
//这是上传文件显示的上传弹框,在右下角 有文件上传时显示 默认是隐藏
<div
v-show="isShowDropUploadFileLists"
class="drog_list"
>
<uploader-list>
<div
slot-scope="props"
class="file-panel"
:class="{ collapse: collapse }"
>
<div class="file-title">
<div class="title">文件列表</div>
<div class="operate">
<el-button
type="text"
:title="collapse ? '展开' : '折叠'"
@click="collapse = !collapse"
>
<i :class="collapse ? 'el-icon-full-screen' : 'el-icon-minus'" />
</el-button>
<el-button
type="text"
title="关闭"
@click="CloseFilesUploadList"
>
<i class="el-icon-close" />
</el-button>
</div>
</div>
<ul class="file-list">
<li
v-for="file in props.fileList"
:key="file.id"
class="file-item"
:class="`file-${file.id}`"
>
<uploader-file
ref="files"
:class="'file_' + file.id"
:file="file"
:list="true"
/>
</li>
<div
v-if="!props.fileList.length"
class="no-file"
>
<i class="iconfont icon-empty-file" /> 暂无待上传文件
</div>
</ul>
</div>
</uploader-list>
</div>
</uploader>
相关js我是单独拎出来了然后通过mixins混入到当前vue文件了
import { GetBatchFilesId, GetDocumentSameNameInfo } from "@/api/file"; //批量上传获取ID,对比上传文件是否跟已存在的同名的两个接口
import { CreateFilePath, CreateFileName } from "@/utils/handleFile";//这个是入参对文件/文件夹路径和名字的处理
export default {
data () {
return {
options: {
target: "http://test.hhh.com.cn/api/Files",//上传地址,如果有文件上传地址不同时 可以是个函数来改变
testChunks: false,//测试每个块是否在服务端已经上传了
allowDuplicateUploads: true, // 一个文件以及上传过了是否还允许再次上传
query: (file, chunk) => { //上传时所带的参数 可以是个函数在选择文件时 自定义(拿到的两个参数分别是Uploader.File 实例、当前块 Uploader.Chunk 以及是否是测试模式)
return {
...file.params,
isUseLastVersionFieldValueWhenUpdate: false, // 請帶false
path: CreateFilePath(file.relativePath, true),
autoIdNamingType: "Auto", // 自动编码
directoryId: 14, // 项目ID
};
},
},
fileStatusText: {//显示的状态
success: "上传成功",
error: "上传失败",
uploading: "上传中",
paused: "已暂停",
waiting: "等待上传",
},
}
},
computed: {
// 获取上传文件实例
uploaderRef() {
return this.$refs.uploader.uploader;
},
},
methods: {
//值得注意的是我这个方法是@files-added="onFilesAdded",是对当前一次性上传的所有文件做的处理,比如说上传5个文件 那就是会获得一个数组里面包括5个文件,这个函数是在file-added全部执行完后走一次
// @file-added="onFileAdded"获取到的单个当前上传文件,按照上传顺序来的,比如说上传5个文件,那这个函数会执行5次
// 全部文件处理
onFilesAdded (files, filelist) {
this.nowUploadFiles = [...files]//当前上传的文件列表保存了一下 后面有同名弹框操作后 方便继续上传文件 不然触发到同名文件弹框了 后续的操作获取不到已经上传到一半的文件了
let getBatchIds = ''
const filesLength = files.length
// 调用文件同名验证接口,这边入参用的都formData格式
var formdata = new FormData();
formdata.append("id", 3);
formdata.append("directoryId", 6);
formdata.append("isReserveDirStructure", true);
this.fileList.forEach((v) => {
formdata.append("paths[]", v);
});
this.fileNameList.forEach((v) => {
formdata.append("filenames[]", v);
});
this.fileList = []
this.fileNameList = []
const getSameFileInfo = new Promise((resolve, reject) => {
formdata.append("autoIdNamingType", "Auto");
GetDocumentSameNameInfo(formdata).then(_res => {
resolve(_res)
}).catch(err => reject(err))
})
if (filesLength > 1) { //多文件或者文件夹上传的时候 入参需要带个批量ID 看自己需求哈
// 批量上传文件
getBatchIds = new Promise((resolve, reject) => {
formdata.append("isTemp", false);
GetBatchFilesId(formdata).then(_res => {
resolve(_res)
}).catch(err => reject(err))
})
}
Promise.all([getSameFileInfo, getBatchIds]).then(res => {
if (res && res.length) {
// 同名文件对比弹框弹出
this.isShowSameFiledialog = !!(res[0] && res[0].length)
this.isShowSameFileInfo = res[0] // 同名文件列表
// 保存批量文件ID
this.BatchUploadId = res[1].BatchUploadId || ''
if (!this.isShowSameFiledialog) {
// 单个文件无同名时直接上传,不显示弹框
console.log(files[0].name)
files.forEach(item => {
item.params = {
sameNameUpdateisTrue: this.sameNameUpdateisTrue, // 遇到同名檔案是否更版
isReserveDirStructure: false,
}
item.resume();
})
// 显示上传文件弹框
this.isShowDropUploadFileLists = true
console.log('单个文件无同名时直接上传,不显示弹框')
}
}
}).catch(err => console.log(err, '哈哈哈'))
},
// 文件上传获取单个文件
onFileAdded (file, fileList) {
const _dataPath = file.relativePath;
// 获取到文件的路径数组和对应的文件名数组
this.fileList.push(CreateFilePath(_dataPath, this.isFromDragDrop));
this.fileNameList.push(CreateFileName(_dataPath));
},
// 根文件上传成功
onFileComplete (rootFile) {
this.$message({
message: "上传成功!",
type: "success",
});
},
// 文件上传失败
onFileError (file) {
this.$message({
message: "上传失败,请重试!",
type: "error",
});
},
// 点击关闭按钮
CloseFilesUploadList () {
this.uploaderRef.cancel();
this.isShowDropUploadFileLists = false;
},
}
}
遇到同名文件弹框的操作
<SameFileInfo
ref="sameFileDailog"
:isshow="isShowSameFiledialog" //显示弹框
:same-file-info="isShowSameFileInfo"//同名文件数据列表
@handelUpdateFile="handelUpdateSameNameFile"
/>
// 同名文件弹框操作
handelUpdateSameNameFile(type) {
if (type === "cancel") { //取消操作
this.nowUploadFiles &&
this.nowUploadFiles.forEach((item) => {
item.ignored = true;
});
this.uploaderRef.cancel(); //关闭上传 uploaderRef是组件uploader的实例
this.isShowDropUploadFileLists = false; //关闭上传文件列表
// 关闭弹框
this.isShowSameFiledialog = false;
return false;
}
if (type === "skip") {//跳过
// 点击跳过
this.sameNameUpdateisTrue = false;
// 过滤掉重名的文件
const _this = this;
_this.nowUploadFiles &&
_this.nowUploadFiles.forEach((v) => {
_this.isShowSameFileInfo.forEach((val) => {
if (val.DocumentName.split(".")[0] === v.name.split(".")[0]) {
v.ignored = true; //给当前上传的文件列表中同名文件都加一个属性,后续过滤掉同名文件不上传
}
});
});
} else if (type === "replace") {
this.sameNameUpdateisTrue = true;
} else if (type === "add") {
this.sameNameUpdateisTrue = false;
}
// 给上传插件赋值(传参)
this.nowUploadFiles &&
this.nowUploadFiles.forEach((item) => {
item.params = {
sameNameUpdateisTrue: this.sameNameUpdateisTrue, // 遇到同名檔案是否更版
isReserveDirStructure: true, // 是否保留本地文件夾結構 (單檔可帶false)
batchUploadId: this.BatchUploadId,
};
if (item.ignored) {
this.uploaderRef.removeFile(item); //如果有同名过滤属性的则选择不上传
}
item.resume();
});
// 关闭弹框
this.isShowSameFiledialog = false;
// 显示上传文件弹框
this.isShowDropUploadFileLists = true;
},
大致逻辑都在这里了
最后贴一下样式代码吧
<style lang="scss">
#uploader_btn {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.drog_list {
position: fixed;
z-index: 20;
right: 15px;
bottom: 15px;
width: 520px;
box-sizing: border-box;
.file-panel {
background-color: #fff;
border: 1px solid #e2e2e2;
border-radius: 7px 7px 0 0;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
.file-title {
display: flex;
height: 40px;
line-height: 40px;
padding: 0 15px;
border-bottom: 1px solid #ddd;
.operate {
flex: 1;
text-align: right;
i {
font-size: 18px;
}
}
}
.file-list {
position: relative;
height: 240px;
overflow-x: hidden;
overflow-y: auto;
background-color: #fff;
transition: all 0.3s;
list-style: none;
padding: 0 2%;
font-size: 12px;
.file-item {
background-color: #fff;
}
::v-deep .uploader-file-size {
text-indent: 0 !important;
}
::v-deep .uploader-file-status {
width: 22%;
}
::v-deep .uploader-file-name {
display: flex;
align-items: center;
.uploader-file-icon {
margin-top: 0;
margin-right: 0;
}
}
::v-deep .uploader-file-meta {
display: none;
}
::v-deep .uploader-file-actions {
width: 12%;
float: right;
}
}
&.collapse {
.file-title {
background-color: #e7ecf2;
}
.file-list {
height: 0;
}
}
}
}
</style>
更多推荐
已为社区贡献11条内容
所有评论(0)