Vue3
一. word
- 安装:npm install docx-preview
- 父页面
<template>
<div>
<DocPreview
v-if="filePath.includes('docx')"
:doc-url="filePath"
/>
</div>
</template>
<script setup>
import DocPreview from '@/components/DocPreview'
const filePath = ref('https://xxxxxxxxxxxx.docx')
</script>
- 组件
路径:@/components/DocPreview
<!-- word 文档阅读 -->
<template>
<div>
<div v-if="message" class="doc-empty">{{ message }}</div>
<div v-else class="doc-render-wraper">
<div ref="fileRef">
<div ref="fileStyleRef"></div>
</div>
</div>
</div>
</template>
<script setup>
import axios from 'axios'
// const docx = require('docx-preview')
import { renderAsync } from 'docx-preview'
const props = defineProps({
// 文档地址
docUrl: {
type: String,
default: ''
}
})
const service = axios.create({
baseURL: props.docUrl,
timeout: 600000
})
const fileRef = ref(null)
const fileStyleRef = ref(null)
const message = ref('')
// 预览
const init = async () => {
const { data } = await service({
method: 'get',
responseType: 'blob'
})
// console.log(data)
if (data.size === 0) {
message.value = '当前文档内容为空,无可阅读内容'
} else {
message.value = ''
renderAsync(data, fileRef.value, fileStyleRef.value)
}
}
watch(
() => props.docUrl,
newVal => {
if (newVal !== null && newVal !== '') {
init()
}
}
)
init()
</script>
<style lang="scss" scoped>
.doc-render-wraper {
width: 840px;
padding-top: 10px;
margin: 0 auto;
overflow-x: auto;
// fileStyleRef css
> div {
border: 1px solid #e6edf5;
}
}
.doc-empty {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #0f5c9f;
background-color: #e6edf5;
width: 100%;
height: 50px;
}
</style>
二. excel
- 安装:npm install @vue-office/excel
- 父页面
<template>
<div>
<XlsxPreview :xlsx-url="filePath" />
</div>
</template>
<script setup>
import XlsxPreview from '@/components/XlsxPreview'
</script>
- 组件
<!-- excel 文档阅读 -->
<template>
<div class="xlsx-preview">
<vue-office-excel :src="source" class="vue-office-excel" />
</div>
</template>
<script setup>
// 引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
// 引入相关样式
import '@vue-office/excel/lib/index.css'
const props = defineProps({
// 文档地址
xlsxUrl: {
type: String,
default: ''
}
})
const source = ref(props.xlsxUrl)
</script>
<style lang="scss" scoped>
.xlsx-preview {
width: 840px;
height: 100%;
padding: 20px 0;
margin: 0 auto;
box-sizing: border-box;
}
.vue-office-excel {
width: 100%;
height: 100%;
border: 1px solid #e5e5e5;
margin: 0 auto;
box-sizing: border-box;
}
</style>
三. ppt
- 官网:https://github.com/meshesha/PPTXjs
demo:https://pptx.js.org/pages/demos.html - 注意:先引入pptjs
- 父文件
<template>
<div>
<PptxPreview :pptx-url="filePath" />
</div>
</template>
<script setup>
import PptxPreview from '@/components/PptxPreview/index.vue'
const filePath = ref("")
</script>
- 组件
<!-- pptx 文档阅读 -->
<template>
<div class="xlsx-preview">
<div class="page-tool">
<div class="page-tool-item" @click="pageZoomOut">放大</div>
<div class="page-tool-item" @click="pageZoomIn">缩小</div>
</div>
<!-- <div style="display: grid; place-content: center; color: darkgrey">pptx文件暂时无法预览~~~</div> -->
<div style="height: 1200px; width: 90%; zoom: 0.5; overflow-y: auto; overflow-x: auto; margin: 0 30px">
<div
id="your_div_id_result"
style="position: relative"
:style="`transform:scale(${size});transform-origin:0% 0%`"
></div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
// 文档地址
pptxUrl: {
type: String,
default: ''
}
})
const size = ref(1)
function init(newVal) {
$('#your_div_id_result').pptxToHtml({
pptxFileUrl: newVal,
slidesScale: '50%'
})
}
onBeforeUnmount(() => {
$('#your_div_id_result').empty()
})
const pageZoomOut = () => {
if (size.value < 3) {
size.value += 0.1
}
}
const pageZoomIn = () => {
if (size.value > 0.8) {
size.value -= 0.1
}
}
watch(
() => props.pptxUrl,
newVal => {
if (newVal) {
setTimeout(() => {
init(newVal)
}, 1000)
}
},
{ immediate: true }
)
</script>
<style lang="scss" scoped>
// import './css/pptxjs.css' import './css/nv.d3.min.css'
.xlsx-preview {
width: 840px;
height: 100%;
// margin-left: 80px;
padding: 20px 0;
// margin: 0 auto;
box-sizing: border-box;
}
.vue-office-excel {
width: 100%;
height: 100%;
border: 1px solid #e5e5e5;
margin: 0 auto;
box-sizing: border-box;
}
.page-tool {
display: flex;
align-items: center;
justify-content: center;
margin-left: 50px;
margin-bottom: 20px;
padding: 8px 0;
// width: 400px;
width: 80%;
text-align: center;
background: #e6edf5;
color: #0f5c9f;
border-radius: 19px;
cursor: pointer;
}
.page-tool-item {
padding: 0 15px;
padding-left: 10px;
cursor: pointer;
}
</style>
- 缺陷
(1)不支持上传jpg格式的图片:若ppt中含有jpg格式的图片,报错
(2)支持仅pptx文件格式
四. pdf
4.1 vue-pdf-embed
功能:放大、缩小、跳转到某页
- 安装: npm install vue-pdf-embed
- 父页面
<template>
<div>
<PdfPreview :key="fileIndex" :pdf-url="filePath" />
</div>
<template>
<script setup>
const fileIndex = ref(0)
const filePath = ref(https://xxxxxxxxxxxxxxx.pdf)
</script>
- 组件
<template>
<div class="pdf-preview">
<div v-if="props.pdfUrl.indexOf('undefined') == -1" v-loading="pdfLoading">
<div class="page-tool">
<div class="page-tool-item" @click="lastPage">上一页</div>
<div class="page-tool-item" @click="nextPage">下一页</div>
<div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
<div class="page-tool-item" @click="pageZoomOut">放大</div>
<div class="page-tool-item" @click="pageZoomIn">缩小</div>
<div class="page-tool-item">前往</div>
<el-input v-model.number="currentPage" style="width: 100px" @input="goToPage(currentPage)" />页
</div>
<div class="pdf-wrap">
<vue-pdf-embed
ref="pdfRef"
:source="{
cMapUrl: 'https://cdn.jsdelivr.net/npm/[email protected]/cmaps/',
url: state.source,
cMapPacked: true
}"
class="vue-pdf-embed"
:style="`transform:scale(${state.scale});transform-origin:0% 0%`"
:page="state.pageNum"
@loading-failed="pdfLoading = false"
@rendered="handleDocumentRender"
/>
</div>
</div>
</div>
</template>
<script setup>
import { defineAsyncComponent } from 'vue'
const { proxy } = getCurrentInstance()
const VuePdfEmbed = defineAsyncComponent(() => import('vue-pdf-embed'))
const props = defineProps({
pdfUrl: {
type: String,
required: true,
default: ''
}
})
const pdfLoading = ref(true)
const currentPage = ref(1)
const state = reactive({
source: props.pdfUrl, // 预览pdf文件地址
pageNum: 1, // 当前页面
scale: 1, // 缩放比例
numPages: 0 // 总页数
})
// 加载完成
const handleDocumentRender = () => {
pdfLoading.value = false
state.numPages = proxy.$refs.pdfRef.pageCount
}
const lastPage = () => {
if (state.pageNum > 1) {
state.pageNum -= 1
currentPage.value = state.pageNum
}
}
const nextPage = () => {
if (state.pageNum < state.numPages) {
state.pageNum += 1
currentPage.value = state.pageNum
}
}
const pageZoomOut = () => {
if (state.scale < 3) {
state.scale += 0.1
}
}
const pageZoomIn = () => {
if (state.scale > 0.8) {
state.scale -= 0.1
}
}
const goToPage = page => {
if (page >= 1 && page <= state.numPages) {
currentPage.value = page
state.pageNum = page
}
}
</script>
<style lang="scss" scoped>
.pdf-preview {
// position: relative;
width: 840px;
// height: 1250px;
padding: 10px 0;
margin: 0 auto;
box-sizing: border-box;
}
.pdf-wrap {
overflow-y: auto;
}
.vue-pdf-embed {
text-align: center;
width: 100%;
border: 1px solid #e5e5e5;
margin: 0 auto;
box-sizing: border-box;
}
.page-tool {
display: flex;
align-items: center;
justify-content: center;
margin: 10px auto;
// width: 400px;
width: 80%;
text-align: center;
background: #e6edf5;
color: #0f5c9f;
border-radius: 19px;
cursor: pointer;
}
.page-tool-item {
padding: 0 15px;
padding-left: 10px;
cursor: pointer;
}
</style>
4.2 iframe
<template>
<div>
<iframe type="application/pdf" :src="filePath"width="800" height="1000">
</iframe>
</div>
<template>
<script setup>
const filePath = ref("")
<script>
五. 视频
- 支持格式:.mov,.mp4
- 父文件
<template>
<div>
<VideoPreview
v-if="subfix == 'mp4' || 'mov')"
:url="videoUrl"
:isExport="isExport"
/>
</div>
</template setup>
<script>
import VideoPreview from '@/components/VideoPreview'
const subfix = ref('mp4') // 视频文件后缀
const videoUrl = ref('')
const isExport = ref(true)
</script>
- 组件
<template>
<div v-if="filePath" style="overflow-x: auto">
<video
oncontextmenu="return false;"
:src="filePath"
:style="`width: ${widths}% `"
class="w-[218px] h-[140px] rounded-[4px] bg-second video"
controls
autoplay
disablePictureInPicture
:controlsList="isDownload ? 'noremoteplayback noplaybackrate' : 'noremoteplayback noplaybackrate nodownload'"
>
<source />
</video>
</div>
</template>
<script setup>
import dragWidthStore from '@/views/satisfiedEngineering/evaluationProcedure/store/dragWidth'
const widths = computed(() => dragWidthStore().width)
const filePath = ref('')
const isDownload = ref(false) // 是否给控件赋予下载权限
const props = defineProps({
url: {
type: String,
default: ''
},
isExport: {
type: Boolean,
default: true,
require: false
}
})
watch(
() => props.url,
newValue => {
filePath.value = newValue
},
{ deep: true, immediate: true }
)
watch(
() => props.isExport,
newValue => {
isDownload.value = newValue
},
{ deep: true, immediate: true }
)
</script>
六:扩展——kkFileView
项目中没涉及到,大致记录一下
-
官网:https://kkfileview.keking.cn/kkFileView-4.1.0-docker.tar
-
支持格式
-
组件
<!-- 文件预览
支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx, xlam, xla, pages 等 Office 办公文档
支持 wps, dps, et, ett, wpt 等国产 WPS Office 办公文档
支持 odt, ods, ots, odp, otp, six, ott, fodt, fods 等OpenOffice、LibreOffice 办公文档
支持 vsd, vsdx 等 Visio 流程图文件
支持 wmf, emf 等 Windows 系统图像文件
支持 psd, eps 等 Photoshop 软件模型文件
支持 pdf ,ofd, rtf 等文档
支持 xmind 软件模型文件
支持 bpmn 工作流文件
支持 eml 邮件文件
支持 epub 图书文档
支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 等 3D 模型文件
支持 dwg, dxf, dwf, iges , igs, dwt, dng, ifc, dwfx, stl, cf2, plt 等 CAD 模型文件
支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本
支持 zip, rar, jar, tar, gzip, 7z 等压缩包
支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp 等图片预览(翻转,缩放,镜像)
支持 tif, tiff 图信息模型文件
支持 tga 图像格式文件
支持 svg 矢量图像格式文件
支持 mp3,wav,mp4,flv 等音视频格式文件
支持 avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf 等视频格式转码预览
支持 dcm 等医疗数位影像预览
支持 drawio 绘图预览
Docker环境部署:
网络环境方便访问docker中央仓库
docker pull keking/kkfileview:4.1.0
网络环境不方便访问docker中央仓库
wget https://kkfileview.keking.cn/kkFileView-4.1.0-docker.tar
docker load -i kkFileView-4.1.0-docker.tar -->
<template>
<div>
<iframe
:src="`${containerUrl}/onlinePreview?url=` + encodeURIComponent(Base64.encode(fileUrl))"
frameborder="0"
class="fileView"
>
</iframe>
</div>
</template>
<script setup>
import { Base64 } from 'js-base64'
const props = defineProps({
// 浏览器访问容器地址
containerUrl: {
type: String,
default: ''
},
// 文档地址
fileUrl: {
type: String,
default: ''
}
})
</script>
<style lang="scss" scoped>
.fileView {
width: 800px;
height: 1020px;
border-width: 1px;
}
</style>