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.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">
<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";
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) => {
return {
...file.params,
isUseLastVersionFieldValueWhenUpdate: false,
path: CreateFilePath(file.relativePath, true),
autoIdNamingType: "Auto",
directoryId: 14,
};
},
},
fileStatusText: {
success: "上传成功",
error: "上传失败",
uploading: "上传中",
paused: "已暂停",
waiting: "等待上传",
},
}
},
computed: {
uploaderRef() {
return this.$refs.uploader.uploader;
},
},
methods: {
onFilesAdded (files, filelist) {
this.nowUploadFiles = [...files]
let getBatchIds = ''
const filesLength = files.length
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) {
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]
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();
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,
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>
|