效果如下:
官网: pdf-vue3 - npm (npmjs.com)
安装
npm i pdf-vue3
使用
<view class="file-item">
<PDF src="/assets/pdf/xxx.pdf"/>
</view>
<script setup lang="ts">
import PDF from 'pdf-vue3';
</script>
封装组件
<template>
<view class="file-item">
<PDF class="pdf-item" :src="pdfData.url" />
</view>
</template>
<script setup lang="ts">
import PDF from 'pdf-vue3';
import { defineProps } from "vue";
const props = defineProps({
pdfData: {
type: Array,
default: () => [],
},
});
</script>
<style scoped lang="scss">
.pdf-item {
width: 100%;
height: 100%;
}
</style>
父组件
<template>
<PDF :pdf-data="pdfData" />
</template
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import PDF from '@/components/pdf.vue';
const pdfData = ref({
url: '/src/assets/pdf/xxx.pdf',
key: '1',
page: '2',
});
</script>
前后端对接
-
由于文件是从后端获取的, 而前端无法在接收后端文件后报错在项目中
-
根据官网, pdf-vue3支持三种方式预览
后端读取文件后转为
base64
返回, 直接返回文件或文件流 无法展示 -
src
The URL or binary data(Uint8Array) or BASE64-encoded of the PDF. string
|Uint8Array
|BASE64
后端
@GetMapping("/preview/{id}")
private void previewPdf(@PathVariable Long id, HttpServletResponse response, String dispositionType) {
try {
// 获取PDF文件信息
PdfFile pdfFile = pdfFileService.getById(id);
if (pdfFile == null) {
throw new RuntimeException("文件不存在");
}
// 构造文件路径
String basePath = System.getProperty("user.dir") + File.separator +
"src" + File.separator + "main" + File.separator +
"resources" + File.separator + "share" + File.separator;
if (pdfFile.getType().equals(PdfFileTypeEnum.SPECIAL_REPORT.getCode())) {
basePath += "气象专报" + File.separator;
} else if (pdfFile.getType().equals(PdfFileTypeEnum.FORECAST.getCode())) {
basePath += "气候预测" + File.separator;
}
File file = new File(basePath + pdfFile.getFileName());
if (!file.exists()) {
throw new RuntimeException("文件不存在");
}
// 读取文件内容为字节数组
byte[] fileBytes = Files.readAllBytes(file.toPath());
// 将字节数组转换为Base64字符串
String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
log.info("base64文件流: " + base64Encoded);
// 设置响应头
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
// 将Base64字符串写入响应
try (OutputStream os = response.getOutputStream()) {
os.write(base64Encoded.getBytes());
os.flush();
}
} catch (Exception e) {
e.printStackTrace();
try {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("{\"message\":\"" + e.getMessage() + "\"}");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
前端
ts封装 axios
请求, 文件预览接口
import axios from 'axios';
import { message } from 'ant-design-vue';
// 创建 Axios 实例
const myAxios = axios.create({
// baseURL: '',
baseURL: 'http://localhost:8090',
timeout: 60000,
withCredentials: true, // 携带登录凭证
});
export async function previewPdfUsingGet(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.previewPdfUsingGETParams
,
options ?: {[key: string]: any}
) {
const { 'id': param0,
...queryParams
} = params;
return request<any>(`/api/pdf/preview/${param0}`, {
method: 'GET',
params: {...queryParams,},
...(options || {}),
});
}
组件调用接口请求
<PDF
v-if="pdfBase64 && !loading"
:src="pdfBase64"
:page="1"
style="height: 100vh"
/>
import PDF from 'pdf-vue3';
const loadPdf = async () => {
try {
// 直接获取base64字符串
console.log('开始加载PDF, ID:', props.pdfData.id);
const response = await previewPdfUsingGet({ id: props.pdfData.id });
// 直接使用返回的 base64 字符串
if (typeof response.data === 'string') {
pdfBase64.value = `data:application/pdf;base64,${response.data}`;
loading.value = false;
} else {
throw new Error('服务器返回的数据格式不正确');
}
console.log('PDF数据加载完成');
} catch (err) {
error.value = '加载PDF文件失败: ' + (err instanceof Error ? err.message : String(err))
console.error('PDF加载错误:', err)
loading.value = false
}
}
onMounted(() => {
if (!props.pdfData?.id) {
error.value = "未提供有效的PDF ID";
return;
}
loadPdf();
});