uniapp编写微信小程序,实现在线直接预览PDF\DOCX及vue-pdf报错RenderingCancelledException {message: “Ren--代码记录

uniapp编写微信小程序,实现在线直接预览PDF文件

需求:后端提供PDF的URL地址,通过webview实现在微信小程序中不分页直接预览PDF文件

一、问题:

客户提供的pdf文件过大18MB,并且有600多页,小程序页面出现白页及等待时间过久等问题,并报以下错误:
vue-pdf多页展示报错

二、解决方法:

1.安装插件

//vue2,对应以下版本
npm install vue-pdf@4.2.0 
npm install pdfjs-dist@2.5.207

2.实现代码:

<template>
  <div>
      <pdf v-for="i in numPages" :key="i" :src="pdfUrl" :page="i" style=" width: 100%">
        </pdf>
        <van-loading v-if="showLoading" class="loading" size="24px" type="spinner" vertical>加载中...</van-loading>
  </div>
</template>
<script>
//引入pdf插件
import pdf from 'vue-pdf'
export default {
  components:{ pdf },
  data() {
    return {
      //pdf-url地址
      pdfFile: '',
      // pdf组件中写的地址
      pdfUrl: '',
      //全部页码
      numPages: undefined,
      // 是否显示loading
      showLoading: true,
      }
  },
  mounted () {
    this.getTitlePdfurl ();
  },
  methods: {
  	 //pdf全页预览
    getTitlePdfurl () {
      //通过设置定时器动态渲染PDF页面的方式成功规避页面加载时间过长及空白情况。
      //当用户点击查看多个PDF时,会先清空当前PDF信息,然后加载新的PDF文件,并利用定时器逐页加载,避免了错误发生。
      this.numPages = null
      let newNumb = null
      this.pdfUrl = pdf.createLoadingTask(this.pdfFile); //this.pdfFile是接口获取的pdf URL地址
      this.pdfUrl.promise.then((pdf) => {
        newNumb = pdf.numPages
        this.showLoading = false
        // 用个定时器解决报错Rendering cancelled
        let timer = setInterval(() => {
          this.numPages += 1
          if (this.numPages === newNumb) {
            clearInterval(timer)
          }
        }, 500)
    },
  },
};
</script>

3.完整代码:
通过点击小程序的列表页,跳转至webview页,将webview中的数据带至本页,通过分类(collectType)判断类别,并通过fileType(文件类型)来判断显示PDF或者DOCX

<template>
  <div class="lawDet">
    <div class="lawDet-hd mlr1">
      <!-- 法律法规 -->
      <div v-if="detailedInfo.collectType==='2'">
        <div class="title mb1 f18">{{detailedInfo.lawName}}</div>
        <div class="mgs f12">
          <div>颁布单位:{{ detailedInfo.formulatingAuthority }}</div>
          <div>法律性质:{{ legalNature[detailedInfo.legalNature]}}</div>
          <div>颁布日期:{{ detailedInfo.releaseDate }}</div>
        </div>
      </div>
      <!-- 审批手续 -->
      <div v-if="detailedInfo.collectType==='3'">
        <div class="title mb1 f18">{{detailedInfo.examineName}}</div>
        <div class="mgs f12">
          <div>创建时间:{{ detailedInfo.createTime }}</div>
          <div class="info">
            <span class="minTit">内容简述:</span>
            <span class="minCon ell2">{{ detailedInfo.examineSketch?detailedInfo.examineSketch:'无' }}</span>
          </div>
        </div>
      </div>
      <!-- 制度建设 -->
      <div v-if="detailedInfo.collectType==='5'">
        <div class="title mb1 f18">{{detailedInfo.institutionalName}}</div>
        <div class="mgs f12" v-if="detailedInfo.institutionalSketch">
          <div>创建时间:{{ detailedInfo.createTime }}</div>
          <div>内容简述:{{ detailedInfo.institutionalSketch?detailedInfo.institutionalSketch:'无' }}</div>
        </div>
      </div>
      <!-- 教育培训 -->
      <div v-if="detailedInfo.collectType==='4'">
        <div class="title mb1 f18">{{detailedInfo.educationName}}</div>
        <div class="mgs f12">
          <div>创建时间:{{ detailedInfo.createTime }}</div>
          <div>所属分类:{{ detailedInfo.educationTypeName }}</div>
          <div class="info">
            <span class="minTit">内容简述:</span>
            <span class="minCon ell2">{{ detailedInfo.educationSketch?detailedInfo.educationSketch:'无' }}</span>
          </div>
        </div>
      </div>
    </div>
    <!-- PDF-->
    <div v-if="fileType==='pdf'" class="pdfArea mlr1">
      <div class="pdf-con" :style="{height: fileHeight + 'px',}">
        <pdf v-for="i in numPages" :key="i" :src="pdfUrl" :page="i" style=" width: 100%">
        </pdf>
        <van-loading v-if="showLoading" class="loading" size="24px" type="spinner" vertical>加载中...</van-loading>
      </div>
    </div>
    <!-- docx区 -->
    <div v-if="fileType==='docx'" class="docxArea" :style="{height: fileHeight + 'px',}">
      <div ref="file" id="docxCon"></div>
    </div>
  </div>
</template>
<script>
import axios from "axios";// 引入axios用来发请求
import pdf from 'vue-pdf'
let docx = require("docx-preview");
export default {
  components: {
    pdf
  },
  data () {
    return {
      detailedInfo: {},
      docxOptions: {
        className: "gwp-docx", // string:默认和文档样式类的类名/前缀
        inWrapper: false, // boolean:启用围绕文档内容的包装器渲染
        ignoreWidth: true, // boolean:禁用页面的渲染宽度
        ignoreHeight: false, // boolean:禁止渲染页面高度
        ignoreFonts: false, // boolean:禁用字体渲染
        breakPages: false, // boolean:在分页符上启用分页
        ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分页
        experimental: false, // boolean:启用实验功能(制表符停止计算)
        trimXmlDeclaration: true, // boolean:如果为true,解析前会从 xml 文档中移除 xml 声明
        useBase64URL: false, // boolean:如果为true,图片、字体等会转为base 64 URL,否则使用URL.createObjectURL
        useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
        showChanges: false, // boolean:启用文档更改的实验性渲染(插入/删除)
        debug: false, // boolean:启用额外的日志记录
      },
      drawer: false,
      //文档类型
      fileType: '',
      //pdf
      pdfUrl: '',
      //全部页码
      numPages: undefined,
      // 是否显示loading
      showLoading: true,
      // 定时器
      timeoutId: null,
      //word 
      wordUrl: '',
      //ppt
      pptUrl: '',
      //文件区域高度
      fileHeight: '',
      //缩放值
      scale: 0.8,
      //法律性质
      legalNature: {
        1: '法律',
        2: '行政法规',
        3: '地方性法规',
      },
    }
  },
  created () {
    document.title = '详细页'
    this.getWxLawDetails()
  },
  mounted () {
    this.getHeight();
  },
  methods: {
    //获取微信小程序传来的多参数
    getWxLawDetails () {
      let wxDetaile = this.$route.query.detailedInfo   //微信小程序带过来的数据
      this.detailedInfo = JSON.parse(wxDetaile)
      //微信小程序带过来的数据
      //this.detailedInfo = { "createUser": "01j6e1h1ymdh44rmy5z6bzye5g", "createTime": "2024-09-09 22:08:23", "updateUser": "01j6e1h1ymdh44rmy5z6bzye5g", "verificationUuid": null,  "id": "01j7bhtf4ffted8f9m7wwkyaxn", "lawName": "建筑设计防火规范(GB 50016-2014,2018年版)",  "oldFileName": "建筑设计防火规范GB 50016-2014(2018).pdf", "newFileName": "law-20240909220805-1725890885785.pdf", "fileType": "pdf", "isRelease": "1", "lawTypeId": "01j6b7tqemame2bbxwbqaa8es5", "filePath": "https://private-storage.anzhengkeji.com.cn/law-20240909220805-1725890885785.pdf?e=1725947890&token=4jQMeYuZ571Jg3rWO-rZheYiqZ790m1Rq41sq7WP:F4oIJWjVzIi9YVLs_MAEuyO7QoU=", "isCollect": "2", "formulatingAuthority": "中华人民共和国住房和城乡建设部", "legalNature": "1", "timeliness": "2", }
      this.pptUrl = this.detailedInfo.filePath
      this.fileType = this.detailedInfo.fileType
      const fileUrl = decodeURIComponent(this.detailedInfo.filePath)
      if (this.fileType === 'pdf') {
        let pdfFile = fileUrl
        this.getTitlePdfurl(pdfFile)
      } else if (this.fileType === 'docx') {
        this.wordUrl = fileUrl
        this.goPreview()
      }
    },
    //预览docx
    goPreview () {
      axios({
        responseType: "blob", // 因为是流文件,所以要指定blob类型
        url: this.wordUrl,
      }).then(({ data }) => {
        let docxCon = document.getElementById("docxCon");
        docx.renderAsync(data, docxCon, null, this.docxOptions); // 渲染到页面
        docxCon.style.height = this.fileHeight / 0.5 + 'px'
        //docx.renderAsync(data, this.$refs.file); // 直接渲染-----渲染到页面
      });
    },
    //DOCX区域高度
    getHeight () {
      var divHeight = document.querySelector('.lawDet-hd').offsetHeight;
      this.fileHeight = window.innerHeight - divHeight - 60
    },
    //pdf全页预览
    getTitlePdfurl (pdfFile) {
      //通过设置定时器动态渲染PDF页面的方式成功规避页面加载时间过长及空白情况。
      //当用户点击查看多个PDF时,会先清空当前PDF信息,然后加载新的PDF文件,并利用定时器逐页加载,避免了错误发生。
      this.numPages = null
      let newNumb = null
      this.pdfUrl = pdf.createLoadingTask(pdfFile);
      this.pdfUrl.promise.then((pdf) => {
        newNumb = pdf.numPages
        this.showLoading = false
        // 用个定时器解决报错Rendering cancelled
        let timer = setInterval(() => {
          this.numPages += 1
          if (this.numPages === newNumb) {
            clearInterval(timer)
          }
        }, 500)
      })
    },
  },
};
</script>
<style lang='scss' scoped>
.lawDet {
  margin-top: 12px;
  .lawDet-hd {
    .title {
      line-height: 24px;
    }
    .mgs {
      background-color: #f7f7f7;
      border-radius: 4px;
      padding: 6px 10px;
      color: #666;
      margin-bottom: 16px;
      line-height: 20px;
      position: relative;
      .collection {
        position: absolute;
        right: 12px;
        top: 37%;
      }
    }
    .info {
      display: flex;
      align-items: baseline;
      .minTit {
        width: 60px;
        flex-shrink: 0;
      }
      .minCon {
        width: 256px;
        line-height: 16px;
        height: 34px;
      }
    }
  }
  .pdf-pagination {
    display: flex;
    justify-content: space-between;
    .btn-pre,
    .btn-next,
    .pageNum {
      background-color: #f4f4f5;
      padding: 6px 14px;
    }
  }
  .pdf-con {
    border: 2px solid #f4f4f5;
    margin-top: 12px;
    height: 550px;
    position: relative;
    overflow-y: auto;
    .loading {
      position: absolute;
      top: 40%;
      left: 50%;
      z-index: 10000;
      margin-left: -26px;
    }
  }
  .docxArea {
    border: 2px solid #f4f4f5;
    margin: 16px;
    overflow: hidden;
    padding-top: 10px;
  }
}
</style>

4.uniapp微信小程序webview页面完整代码:
webview页面中使用cover-view实现悬浮收藏及下载功能

<template>
	<view>
		<web-view :src="src()">
			<cover-view class="collect" v-if="isButtonShow">
				<!-- 收藏 -->
				<cover-view class="btn-collect" :class="{btnActive:isCollect=='1'}" @click="onCollect">
					<cover-image v-show="isCollect==='1'" class="star" src="@/static/img/follow-fill1.png" />
					<cover-image v-show="isCollect==='2'" class="star" src="@/static/img/follow1.png" />
					<cover-view class="conllectTxt">{{isCollect==='1'?'已收藏':'收藏'}}</cover-view>
				</cover-view>
				<!-- 下载 -->
				<cover-view class="btn-collect" @click="onDownload">
					<cover-image class="ico-download" src="@/static/img/ico-download.png" />
					<cover-view class="conllectTxt">下载</cover-view>
				</cover-view>
			</cover-view>
		</web-view>
	</view>
</template>
<script>
	import {
		getReportUserInfo,
		getSysFileInfo
	} from '@/api/login/login.js'
	import {
		getExamineContentInfo
	} from '@/api/detection/index.js'
	import {
		getLawContentInfo,
		editUserCollectInfo
	} from '@/api/law/index.js'
	import {
		getInstitutionalContentInfo,
	} from '@/api/institution/index.js'
	import {
		getEducationContentInfo,
	} from '@/api/education.js' //教育培训接口
	export default {
		data() {
			return {
				pageUrl: 'https://*****gkeji.com.cn/', //线上地址
				//列表带过来的咨询id
				id: '',
				//通过类型区分不同详细页  
				classify: '',
				onBack: '',
				//详细
				detailedInfo: {},
				//用于判断当前用户是否手机号验证
				isPhoneLogin: '',
				isCollect: '', //1 收藏  2  取消
				isButtonShow: false,
				token: '',
			}
		},
		onLoad(e) {
			this.id = e.id;
			this.classify = e.classify;
			this.getDetailed();
		},
		onShow() {
			this.getPhoneLogin();
		},
		mounted() {
			setTimeout(() => {
				this.isButtonShow = true;
			}, 1500); // 1.5后显示按钮
		},
		methods: {
			//获取数据
			getDetailed() {
				//1行业资讯  2法律法规  3审批手续  4教育培训  5制度建设  6应急资源
				if (this.classify === '2') {
					this.getLawContentInfos()
				} else if (this.classify === '3') {
					this.getExamineContentInfos()
				} else if (this.classify === '5') {
					this.getInstitutional()
				} else if (this.classify === '4') {
					this.getEducationInfo()
				}
			},
			//判断用户是否授权手机号
			getPhoneLogin() {
				getReportUserInfo().then(res => {
					let phone = res.data.phone
					if (phone != null) {
						this.isPhoneLogin = true
					} else {
						this.isPhoneLogin = false
					}
				})
			},
			// 教育培训
			async getEducationInfo() {
				const {
					data
				} = await getEducationContentInfo({
					id: this.id
				})
				this.detailedInfo = data
				this.isCollect = data.isCollect //收藏
				this.detailedInfo.isPhoneLogin = this.isPhoneLogin //是否登录
			},
			// 获取详细信息--制度建设
			getInstitutional() {
				const data = {
					id: this.id,
				}
				getInstitutionalContentInfo(data).then(res => {
					this.detailedInfo = res.data
					this.isCollect = res.data.isCollect //收藏
					this.detailedInfo.isPhoneLogin = this.isPhoneLogin //是否登录
					this.detailedInfo.token = uni.getStorageSync('token') //token
				})
			},
			// 获取详细信息--审批手续
			getExamineContentInfos() {
				const data = {
					id: this.id,
				}
				getExamineContentInfo(data).then(res => {
					this.detailedInfo = res.data
					this.isCollect = res.data.isCollect //收藏
					this.detailedInfo.isPhoneLogin = this.isPhoneLogin //是否登录
					this.detailedInfo.token = uni.getStorageSync('token') //token
				})
			},
			// 获取详细信息--法律法规
			getLawContentInfos() {
				const data = {
					id: this.id,
				}
				getLawContentInfo(data).then(res => {
					this.detailedInfo = res.data
					this.isCollect = res.data.isCollect //收藏
					this.detailedInfo.isPhoneLogin = this.isPhoneLogin //是否登录
					this.detailedInfo.token = uni.getStorageSync('token') //token
				})
			},
			//登录成功后回调的收藏方法
			onLoginCollect(e) {
				this.detailedInfo.onBack = e
				this.editUserCollectInfos();
			},
			//点击下载
			onDownload() {
				if (this.isPhoneLogin === true) {
					this.downloadMethod();
				} else {
					let isDownloadDet = 1
					uni.navigateTo({
						url: '/pages/login/login?isDownloadDet=' + isDownloadDet
					})
				}
			},
			//下载方法
			downloadMethod() {
				uni.showLoading({
					title: '正在下载...'
				});
				const data = {
					contentId: this.id,
					fileType: this.detailedInfo.collectType,
				}
				getSysFileInfo(data).then(res => {
					uni.hideLoading()
					uni.showLoading({
						title: '下载并打开文档...'
					});
					let downloadUrl = res.data.filePath
					uni.downloadFile({
						url: downloadUrl, // 文件的本身url
						success: (data) => {
							if (data.statusCode === 200) {
								//文件保存到本地
								uni.getFileSystemManager().saveFile({
									tempFilePath: data.tempFilePath, //临时路径
									filePath: uni.env.USER_DATA_PATH + '/' + this.detailedInfo
										.oldFileName, //自定义文件名
									success: function(res) {
										setTimeout(() => {
											//打开文档查看
											uni.openDocument({
												filePath: res
													.savedFilePath,
												showMenu: true, //是否可以分享
												success: function(res) {
													uni.hideLoading()
												},
												fail: (e) => {
													uni.showToast({
														title: '打开失败',
														icon: "error"
													})
												}
											});
										}, 3000)
									}
								});
							}
						},
						fail: (err) => {
							uni.showToast({
								icon: 'none',
								mask: true,
								title: '失败请重新下载',
							});
						},
					});
				}).catch(err => {
					uni.hideLoading()
				})
			},
			//收藏方法
			onCollect() {
				if (this.isPhoneLogin === true) {
					this.editUserCollectInfos();
				} else {
					let isConllectDet = 1
					uni.navigateTo({
						url: '/pages/login/login?isConllectDet=' + isConllectDet
					})
				}
			},
			//收藏接口
			editUserCollectInfos() {
				let data = {
					collectType: this.detailedInfo.collectType,
					collectContentId: this.id,
					doType: this.isCollect === "2" ? '1' : '2'
				}
				editUserCollectInfo(data).then(res => {
					uni.showToast({
						title: res.msg,
						icon: 'success',
						duration: 500,
					});
					this.isCollect = res.data.doType
				})
			},
			src() {
				return `${this.pageUrl}?detailedInfo=${encodeURIComponent(JSON.stringify(this.detailedInfo))}`
			},
		}
	}
</script>
<style scoped lang="scss">
	.collect {
		position: fixed;
		right: 40rpx;
		z-index: 999;
		bottom: 20%;

		.btn-collect {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			border-radius: 200rpx;
			color: #222;
			background-color: #fff;
			border: 1px solid #d6d6d6;
			width: 116rpx;
			font-size: 22rpx;
			height: 116rpx;
			opacity: 0.8;
			margin-bottom: 20rpx;
		}

		.btnActive {
			background-color: #3278fc;
			border-color: #3278fc;
			color: #fff;
		}

		.conllectTxt {
			margin-top: 2px;
			letter-spacing: 1px;
		}
		.star,
		.ico-download {
			width: 50rpx;
			height: 45rpx;
			z-index: 99999;
		}
	}
</style>
uniapp小程序中实现PDF预览功能,可以采用以下方法。首先,你可以使用web-view组件来装载远程的viewer.html页面,该页面使用pdf.js库来解析和显示PDF文件。这样可以实现基本的预览功能。然而,如果你想要实现手指缩放功能,你可能需要使用其他的解决方案。 一个简单的解决方案是使用uni.downloadFile方法下载PDF文件到本地,然后使用uni.openDocument方法打开该文件。你可以通过后端接口获取PDF文件的URL,并将其作为参数传递给uni.downloadFile方法。下载成功后,你可以使用uni.openDocument方法打开该文件,并指定文件类型为PDF。这样就可以在小程序中实现PDF预览功能,并且支持手指缩放。\[3\] 以下是一个示例代码: ```javascript uni.downloadFile({ url: 'http://example.com/path/to/pdf', // 替换为你的PDF文件URL success: function (res) { var filePath = res.tempFilePath; uni.openDocument({ filePath: filePath, fileType: 'pdf', success: function (res) { console.log('打开文档成功'); uni.hideLoading(); } }); } }); ``` 请注意,你需要将URL替换为你实际的PDF文件URL。这个方法可以在uniapp小程序中实现PDF预览功能,并且支持手指缩放。希望对你有帮助! #### 引用[.reference_title] - *1* *3* [关于使用uniapp在小程序中预览pdf文件可手势缩放的至简方案](https://blog.csdn.net/VastWu/article/details/107663315)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [uni-app 小程序使用 web-view实现在线预览dpf,及H5电子签字](https://blog.csdn.net/zhang0609/article/details/107983830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值