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

2023-10-27

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>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue3+element-plus上传文件,预览文件 的相关文章

随机推荐

  • 首次使用计算机 鼠标没反应,鼠标没反应各种解决方法教程

    我们在使用鼠标的时候开始肯定没问题 但长期使用下来 总会出现一种故障 比如最常见的鼠标没反应的问题 也就是说不管你怎么滑动鼠标 显示器里的光标都不动了 这种问题怎么解决呢 我们要分成有线鼠标和无线鼠标两种情况 一 有线鼠标没反应 一般有线鼠
  • kalilinux搭建DCN漏洞靶场

    kalilinux系统搭建DCN漏洞靶场 前言 安装kalilinux 搭建靶场 WinSCP连接kalilinux实现文件上传 导入镜像 前言 最近想学一下WEB安全 顺便学习一下靶场环境的搭建 之前搭建过webug玩了一下 但自己电脑运
  • 编程的美学标准诌议

    编程的美学标准诌议 做了几年的程序员 虽然自己写的代码还远远没有达到要求 但在日复一日的实践过程中 我逐渐开始信奉一条标准 在实现功能的前提下 简单即是美 其实 编程的过程就好比是一个建模的过程 设计就是将一个现实问题抽象成逻辑模型 而编码
  • git命令使用上传下载详情大全...

    不罗嗦直接上内容 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch a 查看所有的分支 git branch r 查看远程所有分支 git commit am in
  • CISCN(Web Ezpentest)GC、序列化、case when

    目录 REGEXP的一个点 正则 like 默认不区分大小写 当禁用了空格 regexp like的区分大小写的使用方法 CISCN 2022 初赛 ezpentest 卡点 2022 HFCTF babysql 最近又学到了一道新知识 c
  • attrs.xml中declare-styleable 详解(用于自定义控件的属性)

    1 框架定义
  • simulink电力电子仿真(3)单相桥式全控整流电路

    simulink电力电子仿真 3 单相桥式全控整流及有源逆变电路 返回目录 主要是赶上了疫情 然后期末要疯狂补实验报告 就索性写一下吧 万一以后再做电力电路仿真 可能会有用的 也希望可以帮助别人 器件的选择及位置 MATLAB的版本 201
  • 【k8s集群管理工具篇】云原生之部署K8s管理面板KubePi

    k8s集群管理工具篇 云原生之部署K8s管理面板KubePi 一 KubePi介绍 二 环境规划 三 检查本地环境 1 检查k8s集群状态 2 检查kubepi管理主机环境 三 部署KubePi 1 创建KubePi容器 2 检查KubeP
  • Flutter填坑 编译运行不起来

    记录下Flutter中遇到的一些问题 基本上按照Flutter中文网的教程可以完成Flutter环境的搭建 Flutter中文网 https flutterchina club Windows 环境 https flutterchina c
  • sqli-labs 靶场环境搭建

    目录 一 搭建环境所需资源 搭建sqli labs 靶场需要的运行环境 二 搭建过程 1 下载资源 2 创建网站 3 更改配置文件 4 安装数据库 不使用 php7 x 版本的原因 一 搭建环境所需资源 搭建sqli labs 靶场需要的运
  • 21计算机考研国家线,来了!21考研国家线公布!附详细解读!

    原标题 来了 21考研国家线公布 附详细解读 21考研人最近大概都在焦虑的等待国家线 昨天中国农业大学的一条消息直接将 考研国家线 顶上热搜 这不 最新出炉的国家线就来了 21考研国家线公布 21国家线学硕总分线上涨的门类有 经济学 历史学
  • 人工智能还是人工智障

    序言 有的时候感觉有脑子 有的时候感觉没有 到底是有还是没有呢 机器人 有的很智能 有的很智障 是智能的时候可爱 还是在智障的时候可爱 你是惧怕智障还是惧怕人工智能 风言风语 作为一个吵架之王 每次吵架的时候都会想 现在人工智能这么多 但是
  • 【支持向量机】最大间隔超平面及Matlab代码

    线性可分 在特征空间中 有两个训练样本可以通过一条直线区分开 则称为线性可分 而在特征空间大于等于四维时 分开训练样本的平面 称为超平面 我们定义一条直线方程 1 x 1
  • Linux 之exit() 进程退出函数

    进程的退出 linux下进程数量太多会导致系统崩溃 在使用完一个进程之后要及时终止它 进程退出一般有三种方法 1 在main函数中使用 return关键字 使用 return 后系统会调用 exit 函数来终止进程 2 手动调用 exit
  • C++ 关于 protobuf的一些操作

    先是定义部分 下面跟一些例子组成 message DBRoleData uint64 RoleID 2 string Name 6 repeated int64 Action 12 存内置重复单位 message DBRoleLoginAc
  • Kylin 10 SP1(UI)磁盘自行配置lvm

    1 登录服务器 输入 lsblk 查看新磁盘名称 我以sdb为例 sdb1是我为其建立的分区 2 新建分区 fidsk dev sdb 先输入n 新建分区 然后输入p 建立分区 其余选项默认 最后一步输入w保存 3 格式化分区 mkfs x
  • strapi的使用(二)-- Graphql

    一 Graphql 一种为你的API而生的查询语言 可以理解为动态api 一般来说我们都是在后端写好sql查询语句查询数据库数据 前端请求这个api返回的数据是固定的 而Graphql可以让前端去决定请求什么字段回来 二 strapi安装G
  • OPENSSL库的使用-RSA篇

    一 RSA算法简介 RSA公钥加密算法是1977年由Ron Rivest Adi Shamirh和LenAdleman在 美国麻省理工学院 开发的 RSA取名来自开发他们三者的名字 RSA是目前最有影响力的公钥加密算法 它能够抵抗到目前为止
  • 我的GIT练习TWO

    目录 前言 GIT安装教程 Git作者 GIT优点 GIT缺点 为什么要使用 Git GIT练习TWO C1 C2 C3 C4 C5 C6 C7 总结 前言 Git 是一个分布式版本控制及源代码管理工具 Git 可以为你的项目保存若干快照
  • vue3+element-plus上传文件,预览文件

    vue3 ts element plus上传文件 预览文件 场景 使用element plus的el upload标签 手动上传文件 可预览docx xlsx pdf jpg jpeg png 本地资源以及网络资源 1 使用el uploa