??近期做到的項(xiàng)目中有涉及到上傳圖片上傳文件的需求,因?yàn)槭莗c管理后臺(tái),用到了element-plus框架,所以我也一起使用element-plus中的上傳圖片上傳圖片功能,并對(duì)它進(jìn)行封裝成一個(gè)組件,方便在多個(gè)地方使用。
一、效果圖
1、上傳文件、視頻
2、上傳圖片
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-523676.html
二、代碼分析及全部代碼
??在這里上傳圖片和文件是分成了兩個(gè)組件進(jìn)行封裝的,因?yàn)轫?xiàng)目需求要求不一致,所以分開(kāi)了,大家使用時(shí)有需要的話可以將它們合并到一起。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-523676.html
1、上傳文件相關(guān)代碼
<template>
<div class="upload_wrap">
<el-upload
v-if="!props.isDisableUpload"
class="upload"
ref="uploadRef"
:file-list="waitFileList"
:multiple="props.isMultiple"
:limit="props.limitNum"
:accept="props.acceptType"
:auto-upload="false"
:show-file-list="false"
:disabled="props.isDisableUpload"
:on-change="handleChange"
>
<div class="el-upload__text">
<img src="@/assets/images/icon_upload.png" />
<span>上傳文件</span>
</div>
</el-upload>
<div class="template_list">
<div class="template" v-for="(item, index) in waitFileList" :key="index">
<span>
<img src="@/assets/images/icon_link.png" />
</span>
<span class="documentName">{{ item.name }}</span>
<span v-if="!props.isDisableUpload">
<el-icon color="#000000a6" size="16" @click="removeFile(item)"
><Close
/></el-icon>
</span>
<span v-if="isDownLoad" style="paddingleft: 5px">
<img
src="@/assets/images/icon_download.png"
@click="handleDownLoad(item)"
/>
</span>
</div>
</div>
<span class="tips" v-if="!props.isDisableUpload"
>支持{{ acceptTypeDesc }};文件大小不能超過(guò){{ props.maxFileSize }}M</span
>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
import { ElLoading, ElMessage } from "element-plus";
import { request } from "@/api/axios";
import { Close } from "@element-plus/icons-vue";
const emits = defineEmits(["fileSuccess", "fileRemove"]);
interface Props {
acceptType?: string; // 上傳文件類(lèi)型
acceptTypeDesc?: string; // 描述 - 上傳文件類(lèi)型
isMultiple?: boolean; // 是否可批量上傳
limitNum?: number; // 允許上傳文件的最大數(shù)量
isDisableUpload?: boolean; // 是否禁用上傳
maxFileSize?: number; // 文件大小
action?: string;
fileList?: any; // 回顯的文件
isDownLoad?: boolean; // 是否可以下載
}
// 接收父組件傳遞過(guò)來(lái)的參數(shù)
const props = withDefaults(defineProps<Props>(), {
acceptType: ".xls,.doc",
acceptTypeDesc: "doc/xls",
isMultiple: true,
limitNum: 10,
isDisableUpload: false,
maxFileSize: 10,
action: "/activity/resource/uploadFile",
fileList: [],
isDownLoad: false,
});
let waitFileList = ref<any[]>([]);
waitFileList.value = props.fileList;
waitFileList.value?.forEach((item: any) => {
item.name = item.original;
});
watch(
() => props.fileList,
() => {
console.log("props.fileList====>", props.fileList);
waitFileList.value = props.fileList;
waitFileList.value?.forEach((item: any) => {
item.name = item.original;
});
}
);
// 文件變化Handle 這里監(jiān)聽(tīng)上傳文件的變化是一個(gè)一個(gè)接收到變化的,所以文件也是一個(gè)一個(gè)上傳到服務(wù)器上面的
const handleChange = async (file: any, fileList: any[]) => {
// 防止多次執(zhí)行change
const rawFile = file.raw;
const list = props.acceptTypeDesc.split("/");
let acceptTypeList = list.map((its:string)=>{
return getType(its)
})
// 如果要檢索的字符串值沒(méi)有出現(xiàn),則該方法返回 -1
const ars = acceptTypeList.filter((q:string)=>{
return rawFile.type.indexOf(q)>-1
})
// 用于校驗(yàn)是否符合上傳條件
const type = props.acceptTypeDesc.replace("/", ", ");
if (ars.length<1) {
ElMessage.error(`僅支持格式為${type}的圖片`);
return false;
} else if (rawFile.size / 1024 / 1024 > props.maxFileSize) {
ElMessage.error(`文件大小不能超過(guò)${props.maxFileSize}MB!`);
const arr = [...waitFileList.value];
waitFileList.value = arr.filter((item: any) => {
return item.uid != rawFile.uid;
});
return false;
} else {
let formData = new FormData();
formData.append("file", rawFile);
formData.append("fileType", "2");
const loadingInstance = ElLoading.service({
text: "正在上傳",
background: "rgba(0,0,0,.2)",
});
// 上傳到服務(wù)器上面
const requestURL: string = props.action;
request("post", requestURL, formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then(async (res: any) => {
if (res.code == 0) {
loadingInstance.close();
let obj = {
...res.data,
name: res.data.original,
};
emits("fileSuccess", obj);
} else {
loadingInstance.close();
ElMessage.warning(`文件上傳失敗`);
}
})
.catch(() => {
loadingInstance.close();
// ElMessage.warning(`文件上傳失敗`);
});
}
return true;
};
// 校驗(yàn)上傳文件格式
const getType = (acceptType: string) => {
let val = "";
switch (acceptType) {
case "xls":
val = "excel";
break;
case "doc":
val = "word";
break;
case "pdf":
val = "pdf";
break;
case "zip":
val = "zip";
break;
case "xlsx":
val = "sheet";
break;
case "pptx":
val = "presentation";
break;
case "docx":
val = "document";
break;
case "text":
val = "text";
break;
}
return val
};
// 移除文件
const removeFile = (file: any) => {
const arr: any[] = [...waitFileList.value];
waitFileList.value = arr.filter((its: any) => {
return its.id != file.id;
});
emits("fileRemove", waitFileList.value);
};
const handleDownLoad = (row: { ossFile: string }) => {
const str = window.location.href.split("#")[0];
const herf = str.slice(0, str.length - 1);
window.location.href = herf + row.ossFile;
};
</script>
<style lang="scss" scoped>
.upload_wrap {
.upload {
min-width: 468px;
padding-bottom: 10px;
}
.tips {
display: block;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
}
}
:deep().el-upload__text {
width: 106px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.15);
img {
display: block;
width: 14px;
height: 14px;
}
span {
font-size: 14px;
padding-left: 6px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
}
}
.template_list {
padding-bottom: 4px;
}
.template {
display: flex;
align-items: center;
padding: 5px 0;
span {
line-height: 16px;
}
img {
margin-right: 8px;
width: 16px;
height: 16px;
}
.documentName {
margin-right: 12px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
}
</style>
2、上傳圖片相關(guān)代碼及分析
<template>
<div class="avatar-uploader">
<el-upload
class="avatar-uploader"
:show-file-list="false"
:disabled="disabledType"
:auto-upload="false"
accept=".png,.jepg,.jpg"
ref="excelUploadRef"
:on-change="handleChange"
>
<img
v-if="imagesURL || props.imageUrl"
:src="props.imageUrl ? props.imageUrl : imagesURL"
class="avatar"
/>
<div class="upImgBox" v-else>
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
<div>{{ imgUpText }}</div>
</div>
</el-upload>
<div class="upImgText">
{{ imgText }}
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
import { Plus } from "@element-plus/icons-vue";
import { ElMessage, ElLoading } from "element-plus";
import { request } from "@/api/axios";
interface Props {
imageUrl?: string; // 回顯圖片地址
action?: string; // 上傳地址
imgText?: string; // 文字可以不傳
imgUpText?: string; // 上傳按鈕的文字
disabledType?: boolean; // 是否禁用上傳
}
const props = withDefaults(defineProps<Props>(), {
imageUrl: "",
action: "/activity/resource/uploadFile",
imgText: "支持jpg/jpeg/png;文件大小不能超過(guò)2M;封面圖建議尺寸940px*400px",
imgUpText: "上傳封面",
disabledType: false,
});
const imagesURL = ref<string>(props.imageUrl);
const emits = defineEmits(["imgSuccess"]);
const handleChange = (file: any, fileList: any) => {
console.log(file);
console.log(fileList);
let rawFile = file.raw;
if (
rawFile.type !== "image/jpeg" &&
rawFile.type !== "image/png" &&
rawFile.type !== "image/jpg"
) {
ElMessage.error("僅支持格式為jpg, jpeg, png的圖片");
return false;
} else if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error("圖片文件大小不能超過(guò)2MB!");
return false;
} else {
let formData = new FormData();
formData.append("file", rawFile);
formData.append("fileType", "1");
const loadingInstance = ElLoading.service({
text: "正在上傳",
background: "rgba(0,0,0,.2)",
});
// 請(qǐng)求接口上傳圖片到服務(wù)器
let requestURL = props.action;
request("post", requestURL, formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then(async (res: any) => {
console.log(res);
if (res.code == 0) {
loadingInstance.close();
let obj = {
imgUrl: res.data.ossFile,
raw: res.data,
};
emits("imgSuccess", obj);
imagesURL.value = res.data.ossFile;
} else {
loadingInstance.close();
ElMessage.warning(`文件上傳失敗`);
}
})
.catch(() => {
loadingInstance.close();
ElMessage.warning(`文件上傳失敗`);
});
}
return true;
};
watch(
() => props.imageUrl,
() => {
imagesURL.value = props.imageUrl;
}
);
</script>
<style lang="scss" scoped>
:deep().avatar-uploader {
.avatar {
width: 104px;
height: 104px;
display: block;
}
.el-upload {
border: 1px dashed #dcdfe6;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: 0.2s;
background: rgba(0, 0, 0, 0.04) !important;
}
.el-upload:hover {
border-color: #14b194;
}
}
.el-icon.avatar-uploader-icon {
font-size: 16px;
color: rgba(0, 0, 0, 0.45);
text-align: center;
}
.upImgBox {
width: 104px;
height: 104px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
text-align: center;
padding-top: 24px;
box-sizing: border-box;
}
.upImgText {
font-size: 14px;
color: rgba(0, 0, 0, 0.6);
margin-top: 4px;
}
</style>
到了這里,關(guān)于vue3+ts - element-plus封裝上傳文件圖片組件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!