Vue3 使用pdf-vue3 在线预览pdf文件 前后端对接 base64; 支持移动端展示

效果如下:

官网: 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 返回, 直接返回文件或文件流 无法展示

  • srcThe 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();
 });

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值