背景
项目中需要在线预览公司内部的PDF文件,且PC端和移动端均可支持查看
实现方式
一、微软提供的在线预览地址结合iframe:
reviewUrl 为需要预览的 pdf 文件链接
这个方式不仅可以预览 pdf,同时也可以预览 word、ppt、excel 等文件
<iframe :src="'https://view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(reviewUrl)" frameborder="0" title="review" width="100%" height="100%"></iframe>
缺点:
- 有一定的概率会出现网络问题导致无法预览,需要多次刷新重新打开的问题,体验较差
- 在安卓真机设备上会出现打开时直接下载 pdf 文件不能在线预览的问题,不符合需求
二、直接 window.open 打开文档链接
在 iOS 上表现为可以直接在网页中打开,但在安卓端也会变成直接下载文档
三、通过 PDF.js 实现
注意:建议下载低版本,我的是 v2.7.570。版本太高会发现 pdf.js 会报一个版本不匹配的错误,不知道是不是我们的pdf文件版本太低的兼容性问题。
我从v4一直试到v3,最后在这个版本才是最稳定的,测试了一下98%以上的文件都能预览
1、首先在官网下载好所需要的文件,主要内容如下:
将 build 和 web 两个文件夹,整个放到项目中的 public 文件夹下(我的是 Nuxt3 项目,但如果是 Vite 创建的 vue3 项目同样也是放在 public 文件夹下)
2、新建 Preview.vue 组件,用来预览 pdf 文件
因为我的需求是打开弹框进行查看,如果你的项目中不是,那么你打开新页面就行,记得把链接带上。代码如下:
<template>
<el-dialog
title=""
class="preview-dialog"
v-model="dialogVisible"
:destroy-on-close="true"
:append-to-body="true"
:show-close="false"
@closed="handleClose"
>
<div class="close-button" @click.stop="handleClose"></div>
<iframe frameborder="0" :src="previewUrl" width="100%" height="100%"></iframe>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
interface IProps {
reviewUrl?: string;
}
const props = withDefaults(defineProps<IProps>(), {
reviewUrl: "",
});
const emit = defineEmits(["update:modelValue", "emitClosePreview"]);
const dialogVisible = ref(true);
// pdfjs用于预览的url,固定格式,会去项目中的 public 文件夹下找到 web 文件夹中的 viewer.html
const pdfjsFileUrl = '/web/viewer.html?file=';
const previewUrl = ref("");
const handleClose = () => {
emit("emitClosePreview");
};
watch(
() => props.reviewUrl,
newReviewUrl => {
// 如果你预览的是本地的 pdf,那么建议你把 pdf 文件也放到 public 中,这样不会被编译
previewUrl.value = `${pdfjsFileUrl}${encodeURIComponent(newReviewUrl)}`;
},
{
immediate: true,
}
);
</script>
// 弹框的样式我就不贴了
3、在 public/web 下找到 viewer.js 文件,搜索 file origin does not match viewer's
,把这一行注释掉,不然会存在跨域问题
4、在移动端设备上,会发现预览时 pdf 整体内容缩放过小,影响阅读,虽然可以通过手动进行放大,但是这里是可以进行初始设置的。在 viewer.js 文件中,搜索 const DEFAULT_SCALE_VALUE
,然后把默认的值修改为 'page-width'
,这样在移动端预览的时候,就会是最合适设备大小宽度的样式这个方法中,有一个 switch 代码块,可以设置的值如下:
你可以自己设定初始值,以实现你想要的初始化效果。