文件预览功能

我这里实现了图片、excel、docx、pdf 格式的文件在浏览器中预览

一、插件安装

1
npm install @vue-office/docx @vue-office/excel @vue-office/pdf

二、路由配置

我将预览页做成了一个单独的路由页面(一级),因此需要配置下路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import { createRouter, createWebHashHistory } from "vue-router";
import Login from "../views/Login.vue";
import Home from "../views/Home.vue";
import Welcome from "../views/Welcome.vue";
const routes = [
{
path: "/",
redirect: "/login",
meta: { title: "登录页" },
},
{
path: "/login",
name: "login",
component: Login,
meta: { title: "登录页" },
},
{
path: "/home",
name: "home",
component: Home,
redirect: "welcome",
meta: { title: "欢迎页" },
children: [
{
path: "/welcome",
name: "welcome",
component: Welcome,
meta: { title: "欢迎页" },
},
{
path: "/myDoTask",
name: "myDoTask",
component: () => import("@/views/workBench/MyDoTask.vue"),
meta: { title: "我的待办" },
},
{
path: "/myDidTask",
name: "myDidTask",
component: () => import("@/views/workBench/MyDidTask.vue"),
meta: { title: "我的已办" },
},
{
path: "/myApplyTask",
name: "myApplyTask",
component: () => import("@/views/workBench/MyApplyTask.vue"),
meta: { title: "我的申请" },
},
{
path: "/myReadTask",
name: "myReadTask",
component: () => import("@/views/workBench/MyReadTask.vue"),
meta: { title: "我的阅知" },
},
{
path: "/myReadDoneTask",
name: "myReadDoneTask",
component: () => import("@/views/workBench/MyReadDoneTask.vue"),
meta: { title: "我的已阅" },
},
{
path: "/myDraftTask",
name: "myDraftTask",
component: () => import("@/views/workBench/MyDraftTask.vue"),
meta: { title: "我的草稿箱" },
},
{
path: "/marketingGeFix/:WfCode",
name: "marketingGeFix/:WfCode",
component: () => import("@/views/marketing/MarketingGeFix.vue"),
meta: { title: "营销审批-政企产品类(含高校)-固话" },
},
],
},
{
path: "/printDidTask",
name: "printDidTask",
component: () => import("@/views/print/PrintDidTask.vue"),
meta: { title: "已办打印" },
},
// 附件预览页面
{
path: "/preview",
name: "preview",
component: () => import("@/views/preview/preview.vue"),
meta: { title: "附件预览" },
},
{
path: "/403",
name: "403",
meta: {
title: "没有权限",
},
component: () => import("@/views/403.vue"),
},
{
path: "/:pathMatch(.*)",
name: "404",
meta: {
title: "页面不存在",
},
component: () => import("@/views/404.vue"),
},
];

const router = createRouter({
history: createWebHashHistory(),
routes,
base: "/approve/",
});
const whiteList = [
"/403",
"/404",
"/home",
"/welcome",
"/myDoTask",
"/myDidTask",
"/myApplyTask",
"/myReadTask",
"/myReadDoneTask",
"/myDraftTask",
"/printDidTask",
"/printDidTaskPrettyNumber",
"/preview",
];
// 挂载路由导航守卫
router.beforeEach(async (to, from, next) => {
if (to.path === "/login" || to.path === "/403" || to.path === "/404") {
return next();
}
// 获取token
const tokenStr = window.sessionStorage.getItem("token");
if (!tokenStr) {
return next("/login");
} else {
if (whiteList.includes(to.path)) return next();
// 获取to.path对应的menu_id
// const { data } = await getMenuIdByURLAPI({ menu_url: to.path.substring(1) })
// debugger
const menuInfoList = JSON.parse(window.sessionStorage.getItem("menuInfo"));
const result = menuInfoList.filter((item) => {
return item.menu_url === to.path.substring(1);
});
const menuIdList = result.map((item) => item.menu_id + "");
if (result) {
// 根据staff_code 和menu_id获取用户页面访问权限
const userMenuAccessList = JSON.parse(
window.sessionStorage.getItem("userMenuAccess")
);
const res = userMenuAccessList.find((item) =>
menuIdList.includes(item.menu_id)
);
if (res) {
next();
} else {
next("/403");
}
} else {
next("/404");
}
}
});

export default router;

三、预览组件

创建路由中对应的预览组件 preview.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<template>
<div class="previewContainer">
<el-image
v-if="fileType === 'jpg' || fileType === 'png' || fileType === 'bmp'"
:src="fileURL"
@error="errorHandler"
></el-image>
<vue-office-docx
v-if="fileType === 'docx'"
:src="fileURL"
style="height: 100vh"
@error="errorHandler"
/>
<vue-office-excel
v-if="fileType === 'xlsx'"
:src="fileURL"
style="height: 100vh"
@error="errorHandler"
/>
<vue-office-pdf
v-if="fileType === 'pdf'"
:src="fileURL"
@error="errorHandler"
/>
<el-button type="success" round class="returnBtn" @click="$router.back()"
>返回</el-button
>
<el-button
type="success"
round
class="downloadBtn"
@click="download(appendHandler)"
>下载</el-button
>
</div>
</template>

<script setup>
import { useRoute } from "vue-router";
// 引入VueOfficeDocx组件
import VueOfficeDocx from "@vue-office/docx";
// 引入相关样式
import "@vue-office/docx/lib/index.css";
// 引入VueOfficeExcel组件
import VueOfficeExcel from "@vue-office/excel";
// 引入相关样式
import "@vue-office/excel/lib/index.css";
// 引入VueOfficePdf组件
import VueOfficePdf from "@vue-office/pdf";
import { ElMessage } from "element-plus";
import { gdownloadAPI, getDownloadUrlAPI } from "@/api/TaskDetail";
import { ref, onMounted } from "vue";
const route = useRoute();
const fileType = route.params.fileType;
const fileURL = ref(null);
const getfileURL = async () => {
if (fileType === "jpg" || fileType === "png" || fileType === "bmp") {
getDownloadUrlAPI({ fileNameHandler: route.params.appendHandler }).then(
(res) => {
// 通过row.fileName.substring(row.fileName.lastIndexOf('.') + 1)获取文件的后缀名
fileURL.value = res.data.fileDownloadUrl;
}
);
} else {
const { data } = await gdownloadAPI({
fileNameHandler: route.params.appendHandler,
});
const binaryStr = window.atob(data.fileContent);
const ab = new ArrayBuffer(binaryStr.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < binaryStr.length; i++) {
ia[i] = binaryStr.charCodeAt(i);
}
const blob = new Blob([ia]); // new Blob([res])中不加data就会返回下图中[objece objece]内容(少取一层)

const fileReader = new FileReader();
fileReader.readAsArrayBuffer(blob);
fileReader.onload = () => {
// 将 ArrayBuffer 数据转换为 Base64 字符串
fileURL.value = fileReader.result;
};
}
};

onMounted(() => {
getfileURL();
});
const appendHandler = route.params.appendHandler;
const errorHandler = () => {
ElMessage.error("文件预览失败!");
};
const download = async (item) => {
try {
const { data } = await gdownloadAPI({
fileNameHandler: item,
});
const binaryStr = window.atob(data.fileContent);
const ab = new ArrayBuffer(binaryStr.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < binaryStr.length; i++) {
ia[i] = binaryStr.charCodeAt(i);
}
const blob = new Blob([ia]); // new Blob([res])中不加data就会返回下图中[objece objece]内容(少取一层)
const fileName = route.params.filename; // 下载文件名称
const alink = document.createElement("a");
alink.download = fileName;
alink.style.display = "none";
alink.href = URL.createObjectURL(blob);
document.body.appendChild(alink);
alink.click();
URL.revokeObjectURL(alink.href); // 释放URL 对象
document.body.removeChild(alink);
ElMessage.success("下载成功");
} catch {
ElMessage.error("下载失败");
}
};
</script>
<style scoped lang="less">
.previewContainer {
margin: 0;
padding: 0 100px;
background-color: rgb(14, 14, 14);
.returnBtn {
position: fixed;
bottom: 5px;
right: 52%;
opacity: 0.8;
}
.downloadBtn {
position: fixed;
bottom: 5px;
right: 47%;
opacity: 0.8;
}
}
</style>

四、使用预览功能

当在其他地方需要预览文件时,跳转到预览组件,并通过路由传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<el-button type="primary" @click="preview(scope.$index, scope.row)"
>预览</el-button
>
</template>
<script setup>
const preview = async (index, row) => {
// 跳转之前先通知父组件保存页面的状态数据,这样预览返回的时候可以保持原来的状态
emit("saveStateData");
router.push({
name: "preview",
params: {
fileType: row.filename.substring(row.filename.lastIndexOf(".") + 1),
appendHandler: row.appendHandler,
filename: row.filename,
},
});
};
</script>

顺便一提,由于跳转页面之后,原页面的数据丢失,我还将原页面的数据放在了 store 中方便返回时回显。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 congtianfeng
  • 访问人数: | 浏览次数: