1087  
查询码:00001227
vue3+ts+element-plus上传文件,预览文件
作者: 徐文彬 于 2023年01月29日 发布在分类 / 人防组 / 人防前端 下,并于 2023年01月29日 编辑

vue3+ts+element-plus上传文件,预览文件

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

场景:使用element-plus的el-upload标签,手动上传文件,可预览docx,xlsx,pdf,jpg,jpeg,png(本地资源以及网络资源)。

1、使用el-upload标签

在这里插入图片描述

检查上传文件的文件格式与大小

在这里插入图片描述

上传的附件信息在fileList中,组装接口所需数据进行上传

使用docx-preview插件预览docx类型的文件

在这里插入图片描述 在这里插入图片描述

使用xlsx插件预览xlsx文件

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 这里遇到了问题,引入xlsx插件的时候出现"export 'default' (imported as 'XLSX') was not found in 'xlsx'报错 解决:

直接将import XLSX from 'xlsx'改为import * as XLSX from 'xlsx/xlsx.mjs'即可

图片预览

在这里插入图片描述 在这里插入图片描述

pdf预览

在这里插入图片描述 在这里插入图片描述

完整代码

<template>   <el-dialog     v-model="uploadDialogVisible"     title="上传"     width="800px"     label-width="100px"     @close="uploadDialogVisible = false"   >     <el-upload       ref="uploadRef"       v-model:file-list="fileList"       class="upload-demo"       drag       :multiple="true"       :auto-upload="false"       :accept="props.allowType"       :limit="props.limit"       :before-upload="beforeAvatarUpload"       :on-preview="previewFun"     >       <el-icon class="el-icon--upload"><upload-filled /></el-icon>       <div class="el-upload__text">         <em>选择文件</em>       </div>       <template #tip>         <div class="el-upload__tip">           支持格式:{{ props.allowType }};限制大小{{ props.size }}M         </div>       </template>     </el-upload>     <template #footer>       <span class="dialog-footer">         <el-button round @click="cancelFun">取消</el-button>         <el-button round type="primary" @click="submitFun">确定</el-button>         <el-button round type="primary" @click="getFileList"           >获取文件</el-button         >       </span>     </template>   </el-dialog>   <!-- 查看 -->   <viewer ref="fileViewerRef" :dialog-doc="dialogDoc" /> </template> <script setup lang="ts"> /* eslint-disable */ import { defineProps, defineEmits, ref, reactive, computed } from "vue"; import type {   FormInstance,   UploadProps,   UploadUserFile,   UploadRawFile } from "element-plus"; import { ElMessage } from "element-plus"; import { UploadFilled } from "@element-plus/icons-vue"; import { api } from "@/api"; import SparkMD5 from "spark-md5"; import Viewer from "./viewer.vue";  interface Props {   uploadDialogVisible?: boolean;   allowType?: string;   limit?: number;   fileList?: any;   size?: number;   fileExtendId?: string;   fileCategory?: number;   folderName?: string;   systemSource?: string;   uploadUrl?: string; } //props const props: any = withDefaults(defineProps<Props>(), {   uploadDialogVisible: false,   allowType: "doc,docx,jpg,jpeg,png,xlsx,pdf",   limit: 5,   size: 5,   fileExtendId: "",   fileCategory: 2,   folderName: "ceshi",   systemSource: "ceshi",   uploadUrl: "http://192.168.188.3:7001" });  const uploadDialogVisible = computed(() => {   return props.uploadDialogVisible; });  const uploadRef = ref<FormInstance>(); const fileList = ref(([] as any)); const fileExtendId = ref("682D0E35121A4D4E831714CDACD5A18E");  const beforeAvatarUpload = () => {   const flag = ref(true);   fileList.value.forEach((item: any) => {     console.log(item);     const type = item.name.split(".")[1];     if (props.allowType.indexOf(type) == -1) {       ElMessage({         type: "error",         message: `格式错误,支持格式:${props.allowType}!`       });       flag.value = false;       return;     } else if (item.size / 1024 / 1024 > props.size) {       ElMessage.error(`文件最大${props.size}MB!`);       flag.value = false;       return;     }  });   return flag.value; };  //取消 const cancelFun = () => {   emit("cancel", false); };  const submitFun = (formEl: FormInstance | undefined) => {   // 判断是否有文件需要上传   if (fileList.value.length) {     const flag = beforeAvatarUpload();     if (!flag) {       return;     }     // 组合数据     const params = new FormData();     const fileConfigs: any = [];     if (fileList.value.length) {       fileList.value.forEach((item: any, index: number) => {         // 判断一下是不是新上传的         if (item.id) {           fileConfigs.push({             fileId: item.id,             fileName: item.name,             sort: ++index, // 必须从1开始,依次12345往下             md5: ""           });         } else {           params.append("file", item.raw);           const spark = new SparkMD5.ArrayBuffer();           spark.append(item.raw);           const md5 = spark.end();           fileConfigs.push({             fileId: "",             fileName: item.name,             sort: ++index, // 必须从1开始,依次12345往下             md5: md5           });       };       }       );     }     params.append("fileExtendId", fileExtendId.value);     params.append("fileCategory", props.fileCategory);     params.append("folderName", props.folderName);     params.append("systemSource", props.systemSource);     params.append("FileConfigs", JSON.stringify(fileConfigs));     console.log(params);     api.adminCenter.UploadFiles(params).then((res: any) => {       if (res.status.code == 200) {         fileExtendId.value = res.result.fileExtendId;         // 拿到了组合id,继续做业务       }     });  } else {     console.log("直接做业务");  } };  // 获取附件 const getFileList = () => {   api.adminCenter     .GetFileList({       fileExtendIds: fileExtendId.value     })     .then((res: any) => {       if (res.status.code == 200) {         res.result.forEach((ele: any) => {           ele.name = ele.fileOldName;           fileList.value.push(ele);         });       } else {       }     }); };  let dialogDoc: any = ref(false); const fileViewerRef = ref<any>(null); const previewFun = (file: any) => {   console.log(file.halfPath);   dialogDoc.value = true;   let data = file;   // 上传过的文件组成完成的网络路径   if (file.halfPath) {     data.src = `${props.uploadUrl}${file.halfPath}`;  }    const suffix = data.name.split(".")[1];   if (suffix == "docx") {     fileViewerRef.value?.viewDocx(data);  } else if (suffix == "xlsx") {     fileViewerRef.value?.viewXlsx(data);  } else if (suffix == "jpg" || suffix == "jpeg" || suffix == "png") {     fileViewerRef.value?.viewImg(data);  } else if (suffix == "pdf") {     fileViewerRef.value?.viewPdf(data);  } }; // 声明emit const emit = defineEmits(["cancel"]); </script> 
<template>   <!-- doc -->   <el-dialog     v-model="dialogDocxValue"     :title="dialogTitle"     width="80%"     @close="dialogDocxClose"   >     <div ref="docxRef" class="word-div"></div>   </el-dialog>    <!-- xlsx -->   <el-dialog     v-model="dialogXlsxValue"     :title="dialogTitle"     width="80%"     @close="dialogXlsxClose"   >     <div ref="xlsxRef" class="xlsx-div">       <el-tabs v-model="activeName" type="border-card">         <el-tab-pane           v-for="(item, index) in excelSheet"           :key="index"           :label="item.name"           :name="item.name"         >           <div class="table" v-html="item.html"></div>         </el-tab-pane>       </el-tabs>     </div>   </el-dialog>    <!-- 图片 -->   <el-dialog     v-model="dialogImgValue"     :title="dialogTitle"     width="80%"     @close="dialogImgClose"   >     <div class="img-div">       <el-image :src="fileData.src" :alt="fileData.fileOldName" />     </div>   </el-dialog>    <!-- pdf -->   <el-dialog     v-model="dialogPdfValue"     :title="dialogTitle"     width="80%"     @close="dialogPdfClose"   >     <div class="pdf-div">       <iframe         id="pdfRef"         :src="iframeUrl"         frameborder="0"         style="width: 100%; height: 99%"       ></iframe>     </div>   </el-dialog> </template> <script setup lang="ts"> import axios from "axios"; import { defineProps, ref, reactive, computed, nextTick } from "vue"; import { renderAsync } from "docx-preview"; import * as XLSX from "xlsx"; interface Props {   dialogDocx?: boolean;   dialogXlsx?: boolean;   dialogTitle?: string; } const props: any = withDefaults(defineProps<Props>(), {   dialogDocx: false,   dialogTitle: "",   dialogXlsx: false }); const dialogDocxValue: any = ref(false); let dialogTitle = computed(() => {   return props.dialogTitle; }); const fileHtml = ref("");  const docxRef = ref<any>(); // doc 文档预览 const viewDocx = (data: any) => {   docxRef.value = "";   dialogDocxValue.value = true;   console.log(data);   if (data.src) {     // 已上传的文件     axios({       url: data.src,       method: "get",       responseType: "blob"     }).then((res) => {       console.log(res);       if (res.status == 200) {         const content = res.data;         const blob = new Blob([content]);         nextTick(() => {           dialogDocxValue.value = true;           renderAsync(blob, docxRef.value);           dialogTitle = data.fileOldName || data.name;         });       }     });  } else {     // 本地文件     const blob = new Blob([data.raw]);     nextTick(() => {       dialogDocxValue.value = true;       renderAsync(blob, docxRef.value);       dialogTitle = data.fileOldName || data.name;     });  } }; const dialogXlsxValue: any = ref(false); const excelSheet: any = ref([]); const activeName = ref(""); const dialogDocxClose = () => {   dialogDocxValue.value = false;   docxRef.value = ""; }; // xlsx 预览 const viewXlsx = (data: any) => {   dialogXlsxValue.value = true;   console.log(data);   if (data.src) {     axios({       url: data.src,       method: "get",       responseType: "blob"     }).then((res) => {       console.log(res);       if (res.status == 200) {         const content = res.data;         // const blob = new Blob(content);         const reader = new FileReader();         reader.readAsArrayBuffer(content);         reader.onload = function (loadEvent: any) {           const arrayBuffer = loadEvent.target["result"];           const workbook = XLSX.read(new Uint8Array(arrayBuffer), {             type: "array"           });           const list = [];           const sheetNames = workbook.SheetNames;           activeName.value = sheetNames[0];           for (const p of sheetNames) {             let html = "";             try {               html = XLSX.utils.sheet_to_html(workbook.Sheets[p]);             } catch (e) {               html = "";             }             const map = {               name: p,               html: html             };             list.push(map);           }           excelSheet.value = list;           dialogTitle = data.fileName || data.name;         };       }     });  } else {     const blob = new Blob([data.raw]);     const reader = new FileReader();     reader.readAsArrayBuffer(blob);     reader.onload = function (loadEvent: any) {       const arrayBuffer = loadEvent.target["result"];       const workbook = XLSX.read(new Uint8Array(arrayBuffer), {         type: "array"       });       const list = [];       const sheetNames = workbook.SheetNames;       activeName.value = sheetNames[0];       for (const p of sheetNames) {         let html = "";         try {           html = XLSX.utils.sheet_to_html(workbook.Sheets[p]);         } catch (e) {           html = "";         }         const map = {           name: p,           html: html         };         list.push(map);       }       excelSheet.value = list;       dialogTitle = data.fileName || data.name;     };  } };  const dialogXlsxClose = () => {   dialogXlsxValue.value = false;   excelSheet.value = "";   activeName.value = ""; }; const fileData: any = ref({}); const dialogImgValue: any = ref(false); // 图片预览 const viewImg = (data: any) => {   if (data.src) {     // 已上传的图片     fileData.value = data;  } else {     // 本地图片     const freader = new FileReader();     freader.readAsDataURL(data.raw);     freader.onload = (e: any) => {       fileData.value = {         src: e.target.result,         id: new Date(),         fileName: data.fileOldName || data.name       };     };  }   dialogTitle = data.fileOldName || data.name;   dialogImgValue.value = true; }; const dialogImgClose = () => {   dialogImgValue.value = false; };  const dialogPdfValue: any = ref(false); const iframeUrl: any = ref(""); const pdfRef = ref<any>(); const viewPdf = (data: any) => {   if (data.src) {     axios({       url: data.src,       method: "get",       responseType: "blob"     }).then((res) => {       if (res.status == 200) {         // 把文件流转化为url         iframeUrl.value = URL.createObjectURL(res.data);         dialogPdfValue.value = true;       }     });  } else {     iframeUrl.value = URL.createObjectURL(data.raw);     dialogPdfValue.value = true;  } }; const dialogPdfClose = () => {   dialogPdfValue.value = false; }; defineExpose({   viewDocx,   viewXlsx,   viewImg,   viewPdf }); </script> <style scoped lang="scss"> .word-div {   height: calc(70vh);   overflow: auto; } .xlsx-div {   height: calc(70vh);   overflow: auto; } .img-div {   height: calc(70vh);   overflow: auto;   img {     width: 100%;     height: 100%;  } } .pdf-div {   height: calc(70vh);   overflow: auto; } </style> <style lang="scss"> .xlsx-div {  .table-html-wrap table {     border-right: 1px solid #fff;     border-bottom: 1px solid #e8eaec;     border-collapse: collapse;     // margin: auto;  }   .table-html-wrap table td {     border-left: 1px solid #e8eaec;     border-top: 1px solid #e8eaec;     white-space: wrap;     text-align: left;     min-width: 100px;     padding: 4px;  }    table {     border-top: 1px solid #ebeef5;     border-left: 1px solid #ebeef5;     width: 100%;     // overflow: auto;      tr {       height: 44px;     }      td {       min-width: 200px;       max-width: 400px;       padding: 4px 8px;       border-right: 1px solid #ebeef5;       border-bottom: 1px solid #ebeef5;     }  }   .el-tabs--border-card > .el-tabs__content {     overflow-x: auto;  } } </style> 



 推荐知识

 历史版本

修改日期 修改人 备注
2023-01-29 09:54:20[当前版本] 徐文彬 创建版本

 附件
  目录
    知识分享平台 -V 4.8.7 -wcp