目录
前言
纯前端处理文件预览,包含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>
总结
记录一下 希望能帮助到你