VUE3(二十七)自定义upload上传组件(显示上传进度)
2021-04-26 本文已影响0人
camellias__
项目中需要使用到文件上传。我这里自己定义了一个上传文件的组件
支持显示上传进度显示(我这里显示的是真实的上传进度,当然,这个可以根据你自己的需求修改)。
支持多文件上传。
最终效果如下:
20210422091935790.gif代码:
Uploads.vue
<template>
<div class="myUpload">
<!-- 上传文件列表 -->
<div class="myUpload-img center" v-for="(item,index) in mydata" :key="index">
<img :src="item.url" v-if="type=='image'" />
<div class="fileLogo" v-else>
{{item.ext}}
</div>
<!-- 删除文件 -->
<div class="delete" @click="del(item)">
<i class="icon-delete">+</i>
</div>
</div>
<!-- 上传框 -->
<label class="btn center" v-if="(limit == 1 && mydata.length < 1) || limit > 1">
<i class="icon-add">+</i>
<!-- 多图 -->
<input type="file" v-if="multiple == 1 " multiple class="inputfile" @change="handlerUpload($event)" :accept="accept" />
<!-- 单图 -->
<input type="file" v-else class="inputfile" @change="handlerUpload($event)" :accept="accept" />
</label>
</div>
</template>
<style scoped>
@import "../../assets/css/components/pc/Uploads.scss";
</style>
<script>
// 引入js文件
import Uploads from "/@/assets/js/components/pc/Uploads";
// 使用js对象
export default {
...Uploads,
};
</script>
Uploads.ts
// 引入路由
import { useRouter, useRoute } from "vue-router";
import {
PropType,
ref,
watch,
reactive,
toRefs,
inject,
provide
} from "vue";
import { common, userinfo } from "/@/hooks/common.ts";
// 引入公共js文件
import utils from "/@/assets/js/public/function";
// 引入axios钩子
import axios from "/@/hooks/axios.ts";
export default {
name: "Uploads",
/**
* @name: 父组件传递来的参数
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
props: {
// 多文件上传(0:单文件上传,1:多文件上传)
multiple:{
type: Number,
default: 0,
},
// 上传数量
limit:{
type: Number,
default: 0,
},
// 上传地址 url
action:{
type: String,
default: '',
},
// 文件类型
ext:{
type: Array,// 数组类型
default: [".gif", ".jpeg", ".jpg",".png",".bmp",".doc",".docx",".xls",".mp4",".rmvb",".zip"],
},
// 文件大小(mb)
size:{
type: Number,
default: 0,
},
// 列表初始值
data:{
type: Array,// 数组类型
default: [],
},
// 上传文件类型(image | file)
type:{
type: String,
default: 'image',
},
// 随机名(1或者0)
autoName:{
type: Boolean,
default: 1,
}
},
// VUE3语法 setup函数
// setup官方文档:https://www.vue3js.cn/docs/zh/guide/composition-api-setup.html#参数
setup(props: any, content: any)
{
const router = useRouter();
/**
* @name: 声明data
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const data = reactive({
mydata: props.data ? props.data.slice() : [],
accept: props.ext,
});
/**
* @name: 整理目前已有文件
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-02-20
* @param: file object 文件对象
* @param: obj object 文件上传成功之后返回的信息对象
*/
const isImg = (file:any, obj:any) => {
if (props.type == "image")
{
let fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = function (ev:any) {
// 这是base64文件编码
// obj.url = ev.target.result;
if(props.limit == 1)
{
data.mydata = [];
}
data.mydata.push(obj);
};
}
else
{
if (props.limit == 1)
{
data.mydata = [];
}
data.mydata.push(obj);
}
};
/**
* @name: 删除文件
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-02-20
* @param: item object 文件信息
*/
const del = (item:any) => {
data.mydata = data.mydata.filter(function (obj:any) {
return obj != item;
});
};
/**
* @name: 组装上传数据(可多文件上传)
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-02-20
* @param: e obj 文件流
*/
const handlerUpload = (e:any) => {
var file = '';
// 判断文件上传数量是否超限
if (data.mydata.length >= props.limit)
{
utils.alertMsg(2000, '上传文件数量已达到上限!'); return;
}
for (var i = 0; i < e.target.files.length; i++)
{
// 判断文件上传数量是否超限
if (data.mydata.length >= props.limit)
{
utils.alertMsg(2000, '上传文件数量已达到上限!'); return;
}
file = e.target.files[i];
// 上传文件信息
let dataObj = {
file: file,
ext: data.accept,
size: props.size,
autoName: props.autoName == 0 ? props.autoName : 1
};
// 调用上传方法
postUpload(dataObj)
.then(function (res: any) {
let obj = res.data;
isImg(file, obj);
utils.alertMsg(2000, '操作成功!'); return;
})
.catch(function (error: any) {
console.log(error);
utils.alertMsg(2000, error.data.msg); return;
});
}
};
/**
* @name: 上传接口
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-02-18
* @param: data object 上传文件数据对象
*/
const postUpload = (data:any) => {
var obj = new FormData();
for (let item in data)
{
obj.append(item, data[item]);
}
let config = {
headers: {
"Content-Type": "multipart/form-data"
},
onUploadProgress: (e:any) => {
var completeProgress = ((e.loaded / e.total) * 100) | 0;
// props.progress = completeProgress; //上传过程
// 关闭 上传进度显示
utils.alertLoadExec(false);
utils.alertLoadExec(true, '上传进度:'+completeProgress+'%');
}
};
return new Promise(function (resolve, reject) {
axios
.post(props.action, obj, config)
.then(function (res) {
// 关闭 上传进度显示
utils.alertLoadExec(false);
if (res.data.code == 1)
{
resolve(res);
}
else
{
reject(res);
}
})
.catch(function (error) {
reject(error);
// 关闭 上传进度显示
utils.alertLoadExec(false);
});
});
}
/**
* @name: 将data绑定值dataRef
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const dataRef = toRefs(data);
return {
isImg, handlerUpload, postUpload, del,
...dataRef
}
}
};
Uploads.scss
i {
font-style: normal;
}
.myUpload {
display: flex;
}
.inputfile {
width: 0px;
height: 0px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.btn {
width: 200px;
height: 200px;
border-radius: 4px;
font-size: 3rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border: 1px dashed rgb(107 60 60);
color: rgb(72 41 41);
}
.btn:hover {
color: #6bc7ff;
border-color: #6bc7ff;
}
.myUpload-img {
width: 200px;
height: 200px;
margin-right: 10px;
position: relative;
border-radius: 4px;
border: 1px dashed#ccc;
}
.myUpload-img:hover .delete {
display: flex;
}
.myUpload-img:hover {
border-color: red;
}
.myUpload-img img {
width: 100%;
height: 100%;
}
.myUpload-img .fileLogo {
color: #adadad;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: absolute;
top: 0;
bottom: 0;
text-transform: uppercase;
font-size: 3rem;
}
.myUpload-img .delete {
width: 100%;
height: 100%;
border-radius: 4px;
position: absolute;
background: rgba(0, 0, 0, 0.4);
top: 0;
bottom: 0;
display: none;
align-items: center;
justify-content: center;
cursor: pointer;
}
.icon-delete {
color: red;
font-size: 3rem;
transform: rotate(45deg);
}
.center{
margin:auto;
}
上传进度弹窗代码:
utils
.
alertMsg
调用实例:父组件传入子组件的参数,我在子组件ts文件中都有注释。
<Uploads class="upload" :limit="1" :type="'image'" :ext="ext" :data="userLogoInfo"
:action="'后端上传地址'" :autoName="1" :size="5*1024*1024" :multiple="0">
</Uploads>
以上大概是我自定义上传组件的全部代码。
有好的建议,请在下方输入你的评论。
欢迎访问个人博客
https://guanchao.site