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>

总结

记录一下 希望能帮助到你

相关推荐
橙子家25 分钟前
浏览器缓存之【结构化数据库与缓存】: IndexedDB、Cache storage 和 Storage buckets
前端
user205855615181330 分钟前
X6 中边悬浮置顶,规避 `mouseleave` 事件丢失问题
前端
李明卫杭州32 分钟前
CSS aspect-ratio 属性完全指南
前端
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘3 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆3 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师4 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆4 小时前
VSCode自动格式化三要素
前端
爱勇宝5 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员