vue3笔记(19-3)文件预览

经过调研发现,开源库中对docx预览支持较多,doc未找到合适可用的库,包括微软官方js预览插件也仅支持docx。
本篇是对预览组件的封装,可支持docx、jpg、png、txt文件预览

文件预览组件编写

这里以弹窗形式展示预览文件,最终效果如下:
文件预览

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
<template>
<div class="preview-list">
<iframe
v-if="txtUrl"
:src="txtUrl"
frameborder="0"
></iframe>
<el-dialog
title="文件预览"
v-model="dialogVisible"
class="dialog-file"
@close="handleCancle"
>
<div v-if="imgUrl" class="img-prew">
<img :src="imgUrl" alt="" />
</div>
<div v-if="docxFile" class="docx-wrap">
<div ref="docxContainer"></div>
</div>
</el-dialog>
</div>
</template>

<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { getFileType, createUrl } from '@/utils/file'
import * as docx from 'docx-preview'

const props = defineProps<{
fileObj: Object
}>()
const state = reactive({
imgUrl: '',
txtUrl: '',
docFile: false,
docxFile: false,
docValue: null
})
const { imgUrl, txtUrl, docxFile } = toRefs(state)
const dialogVisible = ref(false)
const fileTypeMap = {
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
pdf: 'application/pdf',
png: 'image/png',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
txt: 'text/plain'
}
const docxContainer = ref(null)

// 查看
const handleqaPreviewFileRaw = () => {
const fileRaw = props.fileObj.fileRaw
const name = props.fileObj.name
let suffix = getFileType(name)
const type = fileTypeMap[suffix]

if (suffix == 'pdf') {
const blob = new Blob([fileRaw], { type })
const url = createUrl(blob)
window.open(url)
} else if (suffix == 'txt') {
const blob = new Blob([fileRaw], { type })
const url = createUrl(blob)
state.txtUrl = url
dialogVisible.value = true
} else if (suffix == 'docx') {
state.docxFile = true
dialogVisible.value = true
nextTick(() => {
docx.renderAsync(fileRaw, docxContainer.value).then((x) => console.log('docx: finished', x))
})
} else if (suffix == 'png' || suffix == 'jpg' || suffix == 'jpeg') {
const url = createUrl(fileRaw)
state.imgUrl = url
dialogVisible.value = true
} else {
ElMessage.info('本文件暂不支持预览,请直接下载后查看,谢谢!')
}
}

const handlePreviewClear = () => {
state.docFile = false
state.docxFile = false
state.imgUrl = ''
state.txtUrl = ''
}

const handleCancle = () => {
dialogVisible.value = false
}

onUnmounted(() => {
dialogVisible.value = false
})
defineExpose({ handlePreviewClear, handleqaPreviewFileRaw })
</script>

<style lang="scss" scoped>
.preview-list {
margin-top: 20px;
.img-prew {
width: 600px;
margin: 0 auto;
img {
width: 100%;
}
}
.docx-wrap {
width: 100%;
}
}
</style>

文件预览组件使用

1
2
3
4
5
6
7
8
9
<ul class="filebox">
<li v-for="(file, index) in detail['attachment_info']" :key="index">
<div class="format-file-name">{{ file.name }}</div>
<div class="one">
<span class="fileop" @click="handlePreview(file, 'tracechip')">查看</span>
</div>
</li>
</ul>
<file-preview ref="fileRef" :fileObj="fileObj"></file-preview>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const handlePreview = (file, name: string) => {
lookFile({
attachment_uid: file.uid,
bucket_name: name
})
.then((res) => {
handleqaPreviewFileRaw(res.data, file.name)
})
.catch((error) => {
console.log(error)
})
}

// 查看
const handleqaPreviewFileRaw = (fileRaw, name) => {
fileRef.value.handlePreviewClear()
state.fileObj.fileRaw = fileRaw
state.fileObj.name = name
fileRef.value.handleqaPreviewFileRaw()
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!