https://ext.dcloud.net.cn/plugin?id=28856
概述
ux-pdf 是一个基于 uni-app 框架开发的 PDF 合同阅读预览组件,主要用于预览隐私协议、合同类 PDF 文件。该组件基于 pdfh5 进行开发,支持多平台兼容(APP、小程序、H5),并提供阅读完成检测和倒计时阅读功能。
特性
- ✅ 多平台兼容:支持 APP(Android、iOS、Harmony)、微信小程序、H5
- ✅ 阅读完成检测:滚动到 PDF 最后一页触发回调事件
- ✅ 倒计时阅读:支持设置阅读倒计时,计时完成触发回调事件
- ✅ 按钮状态控制:根据阅读进度和倒计时自动控制"已阅读"按钮状态
- ✅ Vue2/Vue3 兼容:采用选项式 API 编写,兼容两个版本
- ✅ 完整事件回调:提供 ready、complete、error、scroll、pagechange 等事件
安装
uni_modules 方式
组件已打包为 uni_modules 形式,直接放置在项目的 uni_modules 目录下即可使用,无需额外配置。
Props 属性
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| url | String | - | 是 | PDF 文件地址(支持本地路径和远程 URL) |
| viewHeight | String | "100%" | 否 | PDF 预览区域高度 |
| showBottom | Boolean | true | 否 | 是否显示底部按钮栏 |
| disabled | Boolean | true | 否 | 初始按钮禁用状态 |
| showTimer | Boolean | false | 否 | 是否显示倒计时 |
| readTimer | Number | 20 | 否 | 倒计时秒数 |
| btnStyle | Object | {} | 否 | 自定义按钮样式 |
| needReadAllPage | Boolean | true | 否 | 是否需要阅读到最后一页才能点击按钮 |
| debug | Boolean | false | 否 | 是否开启调试日志 |
| options | Object | 见下方 | 否 | pdfh5 配置选项 |
options 配置项
javascript
{
cMapUrl: "https://unpkg.com/pdfjs-dist@3.8.162/cmaps/", // 字体映射文件地址
lazy: false, // 是否懒加载
withCredentials: true, // 是否携带凭证
renderType: "canvas", // 渲染类型:canvas 或 svg
maxZoom: 3, // 最大缩放倍数
scrollEnable: true, // 是否允许滚动
zoomEnable: true // 是否允许缩放
}
Events 事件
| 事件名 | 触发时机 | 回调参数 |
|---|---|---|
| ready | PDF 加载完成,准备就绪 | totalPages - PDF 总页数 |
| complete | PDF 渲染完成 | { status, msg, totalPages, time } |
| error | PDF 加载失败 | { status, msg, time } |
| scroll | 滚动时触发 | { scrollTop, currentNum, totalPages } |
| pagechange | 页码变化时触发 | { currentNum, totalNum } |
| onReachLastPage | 滚动到最后一页时触发 | { totalPages } |
| onTimerComplete | 倒计时完成时触发 | { readTimer } |
| onClickReader | 点击"我已阅读"按钮时触发 | 无 |
Slots 插槽
| 插槽名 | 说明 |
|---|---|
| default | 底部按钮栏内容,默认显示"我已阅读"按钮(仅H5/小程序端支持) |
使用示例
基础用法
vue
<template>
<view class="container">
<ux-pdf :url="pdfUrl" />
</view>
</template>
<script>
export default {
data() {
return {
pdfUrl: 'https://example.com/contract.pdf'
}
}
}
</script>
带倒计时和阅读完成检测
vue
<template>
<view class="container">
<ux-pdf
:url="pdfUrl"
:show-timer="true"
:read-timer="30"
:need-read-all-page="true"
@on-reach-last-page="handleLastPage"
@on-timer-complete="handleTimerComplete"
@on-click-reader="handleComplete"
/>
</view>
</template>
<script>
export default {
data() {
return {
pdfUrl: 'https://example.com/contract.pdf'
}
},
methods: {
handleLastPage(e) {
console.log('已滚动到最后一页', e)
},
handleTimerComplete(e) {
console.log('倒计时完成', e)
},
handleComplete() {
console.log('用户点击了已阅读按钮')
uni.showToast({ title: '提交成功', icon: 'success' })
}
}
}
</script>
自定义按钮样式
vue
<template>
<view class="container">
<ux-pdf
:url="pdfUrl"
:btn-style="btnStyle"
/>
</view>
</template>
<script>
export default {
data() {
return {
pdfUrl: 'https://example.com/contract.pdf',
btnStyle: {
background: '#4E70F6',
color: '#ffffff',
borderRadius: '40rpx',
width: '600rpx'
}
}
}
}
</script>
使用自定义插槽(仅H5/小程序端支持)
vue
<template>
<view class="container">
<ux-pdf :url="pdfUrl">
<view class="custom-btn-group">
<button class="btn-agree" @click="handleAgree">同意</button>
<button class="btn-disagree" @click="handleDisagree">不同意</button>
</view>
</ux-pdf>
</view>
</template>
<script>
export default {
data() {
return {
pdfUrl: 'https://example.com/contract.pdf'
}
},
methods: {
handleAgree() {
console.log('用户同意')
},
handleDisagree() {
console.log('用户不同意')
}
}
}
</script>
<style scoped>
.custom-btn-group {
display: flex;
justify-content: space-around;
width: 100%;
padding: 20rpx;
}
.btn-agree {
background: #4E70F6;
color: #ffffff;
}
.btn-disagree {
background: #f0f0f0;
color: #333;
}
</style>
开启调试日志
vue
<template>
<view class="container">
<ux-pdf
:url="pdfUrl"
:debug="true"
/>
</view>
</template>
开启 debug 属性后,控制台会输出详细的调试日志,包括:
- 组件初始化状态
- PDF 加载进度
- 脚本加载状态
- 消息传递记录
按钮状态逻辑
| needReadAllPage | 按钮可点击条件 |
|---|---|
| true(默认) | 滚动到最后一页 OR 倒计时完成 |
| false | 倒计时完成 |
说明 :当 needReadAllPage 为 true 时,满足以下任一条件按钮变为可点击:
- 用户滚动到 PDF 最后一页
- 倒计时完成
APP端工作原理
PDF URL(本地或远程)
↓
APP端下载PDF文件到本地
↓
读取为base64数据URL
↓
通过URL参数传递给web-view
↓
pdf-preview.html解析参数并渲染PDF
↓
通过uni.postMessage传递事件回调
浏览器兼容性
| 平台 | 支持情况 |
|---|---|
| H5 | ✅ 支持 |
| 微信小程序 | ✅ 支持 |
| APP(iOS) | ✅ 支持 |
| APP(Android) | ✅ 支持 |
| APP(Harmony) | ✅ 支持 |
注意事项
-
PDF 文件跨域问题:如果 PDF 文件来自外部服务器,需要确保服务器配置了正确的 CORS 响应头。
-
字体映射文件:组件默认使用 CDN 加载字体映射文件(cmaps),如果在内网环境使用,需要配置内网地址。
-
Worker 脚本 :PDF.js 的 Worker 脚本通过 CDN 加载(
https://unpkg.com/pdfjs-dist@2.11.338/build/pdf.worker.min.js),确保网络环境可以访问该地址。如需内网部署,可修改 pdfh5.js 中的workerSrc配置。 -
文件体积 :
pdf.js文件较大(约 500KB),建议在生产环境中使用压缩版本。 -
内存管理 :组件会在
beforeDestroy生命周期中清理定时器,避免内存泄漏。 -
APP端自定义样式 :APP端使用独立 HTML 页面渲染,如需自定义按钮样式,需修改 pdf-preview.html 文件。
-
APP端插槽限制:APP端由于使用 webview 独立渲染,自定义插槽功能暂不支持。
-
APP端本地文件 :APP端支持本地文件路径(以
/开头)和远程 URL,远程 URL 会自动下载到本地后再渲染。
更新日志
v1.2
- 支持多平台 PDF 预览 APP (Android,iOS,Harmony OS),小程序,H5
- APP端支持线上 PDF 文件
- 优化阅读完成检测(滚动到最后一页)
- 实现倒计时阅读功能
- 兼容 Vue2 和 Vue3
技术栈
- 框架:uni-app
- PDF 渲染:pdfh5 + pdf.js
- 渲染引擎:Canvas API
- 样式:SCSS
- APP端:web-view 组件