Vue在线预览excel、word、ppt等格式数据。

目录

前言

1.安装库

2.预览文件子组件代码

3、新建store/system.ts

4、父页面进行使用

总结


前言

纯前端处理文件预览,包含excel、word、ppt、txt等格式,不需要后端服务器进行部署,并且内网也可以使用。


1.安装

c 复制代码
npm install @vue-office/docx @vue-office/excel @vue-office/pdf
# 或
yarn add @vue-office/docx @vue-office/excel @vue-office/pdf

2.预览文件子组件代码

javascript 复制代码
<template>
  <div class="fileView">
    <n-modal v-model:show="fileViewVisible">
      <n-card
        style="
          width: 65%;
          position: fixed;
          top: 50px;
          left: 50%;
          transform: translateX(-50%);
        "
        :title="sysStore.fileViewInfo.name"
        :bordered="true"
        size="medium"
        role="dialog"
        aria-modal="true"
      >
        <template #header-extra>
          <n-button circle @click="fileViewVisible = false">
            <template #icon>
              <n-icon>
                <Close />
              </n-icon>
            </template>
          </n-button>
        </template>
        <div>
          <iframe
            v-if="sysStore.fileViewInfo.fileType === 'txt'"
            style="width: 100%; height: calc(100vh - 190px)"
            :src="sysStore.fileViewInfo.viewUrl"
            frameborder="0"
          ></iframe>
          <vue-office-pdf
            v-if="sysStore.fileViewInfo.fileType === 'pdf'"
            style="width: 100%; height: calc(100vh - 180px)"
            :src="sysStore.fileViewInfo.viewUrl"
            frameborder="0"
          ></vue-office-pdf>
          <vue-office-docx
            v-if="sysStore.fileViewInfo.fileType === 'doc'"
            style="width: 100%; height: calc(100vh - 180px)"
            :src="sysStore.fileViewInfo.viewUrl"
            frameborder="0"
          ></vue-office-docx>
          <vue-office-excel
            v-if="sysStore.fileViewInfo.fileType === 'xlsx'"
            style="width: 100%; height: calc(100vh - 180px)"
            :src="sysStore.fileViewInfo.viewUrl"
            frameborder="0"
          ></vue-office-excel>
        </div>
      </n-card>
    </n-modal>
  </div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import useSystemStore from "@/store/system";
import { Close } from "@vicons/ionicons5";
// 引入VueOffice组件
import VueOfficeDocx from "@vue-office/docx";
import VueOfficeExcel from "@vue-office/excel";
import VueOfficePdf from "@vue-office/pdf";
// 引入相关样式
import "@vue-office/docx/lib/index.css";
import "@vue-office/excel/lib/index.css";


const sysStore = useSystemStore();

const fileViewVisible = ref(false);

const show = () => {
  fileViewVisible.value = true;
};

// 监听外部变化
watch(() => props.visible, (newVal) => {
  fileViewVisible.value = newValue
}, {
 immediate: true
})
// 暴漏show给父组件使用
defineExpose({
  show,
});
</script>
<style lang="less" scoped></style>

3、新建store/system.ts

代码如下:

javascript 复制代码
import { defineStore } from "pinia";

interface State {
  fileViewInfo: any; // 文件预览信息
}

const useSystemStore = defineStore("system", {
  state: (): State => ({
    fileViewInfo: {},
  }),
  actions: {
    setFileViewInfo(val: any) {
      this.fileViewInfo = val;
    },
  },
});

export default useSystemStore;

4、父页面进行使用

javascript 复制代码
<template>
  <n-space class="file-view" style="gap: 8px 8px" :inline="true">
    <div
      class="file-item"
      v-for="(file, index) in fileComp"
      :key="index"
      @click="fileView(file)"
    >
      <div class="file-icon">
        <img width="28" :src="file.iconIamge" alt="" />
      </div>
    </div>
  </n-space>
  <FilePreviewDialog v-model:visible="obj.showDialog" ref="filePreviewDialogRef" />
</template>
<script lang="ts" setup>

import { computed, ref } from "vue";
// 以下icon是不同后缀名的文件图片 可要可不要
import excelImg from "@/assets/images/fileIcon/excel.png";
import pdfImg from "@/assets/images/fileIcon/pdf.png";
import wordImg from "@/assets/images/fileIcon/word.png";
import textImg from "@/assets/images/fileIcon/text.png";
import unknownImg from "@/assets/images/fileIcon/unknown.png";
import { getFileSize } from "@/utils/useFunc";
import useSystemStore from "@/store/system";
import FilePreviewDialog from "@/components/FilePreviewDialog.vue";

const filePreviewDialogRef = ref<any>();
const props = defineProps({
  files: {
    type: [Object,Array],
    required: true,
  },
  role: {
    type: String,
  },
});

// 引入vuex
const sysStore = useSystemStore();

// 文件信息
const obj = reactive({
  showDialog: false, // 是否展示附件
  fileUrl: [] // 附件地址
})

const getIcon = (type: string) => {
  type = type.toLowerCase();
  let fileType: "doc" | "pdf" | "xlsx" | "txt" | "" = "";
  let iconIamge = "";
  const docMap = [
    "doc",
    "docx",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  ];
  const pdfMap = ["application/pdf", "pdf"];
  const xlsxMap = [
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "xls",
    "xlsx",
  ];
  const textMap = ["txt", "text/plain", "text"];
  if (docMap.includes(type)) {
    fileType = "doc";
    iconIamge = wordImg;
  } else if (pdfMap.includes(type)) {
    fileType = "pdf";
    iconIamge = pdfImg;
  } else if (xlsxMap.includes(type)) {
    fileType = "xlsx";
    iconIamge = excelImg;
  } else if (textMap.includes(type)) {
    fileType = "txt";
    iconIamge = textImg;
  } else {
    fileType = "";
    iconIamge = unknownImg;
  }
  return {
    fileType,
    iconIamge: iconIamge,
  };
};

// 获取文件数据
const fileView = async(item) => {
const {id} = item
const res = await getPolicy(id)
const {url,name,size,mime_type} = res.data
// 这里拿到的数据:url:完整的url文件流地址
 // name: 文件名
 //size: 文件字节大小
 // mime_type: 文件对应的类型 譬如txt对应 text/plain
// 获取文件后缀类型
const {fileType} = getIcon(mime_type)
const fileInfo = {
  name,
  fileType,
  type: mime_type,
  size,
  viewUrl: url
}
 // 更新文件信息
 sysStore.setFileViewInfo(fileInfo);
// 先关闭
obj.showDialog = false
// 确保dom更新后再次打卡
await nextTick()
obj.showDialog = true
};




</script>



<style lang="less" scoped>
.file-view {
  .file-item {
    display: flex;
    align-items: center;
    border: 1px solid var(--baseColor);
    padding: 8px;
    cursor: pointer;
    min-width: 240px;
    max-width: 300px;
    border-radius: 5px;
    .file-icon {
      margin-right: 5px;
    }
    .file-info {
      max-width: calc(100% - 28px);
      .file-size {
        font-size: var(--fontSizeSmall);
      }
    }
  }
}
</style>

总结

记录一下 希望能帮助到你

相关推荐
To_OC1 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC1 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic2 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy2 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志2 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble3 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长4 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯4 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜5 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司5 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能