前情:需要在app内嵌的weixin项目将页面转成PDF并下载。

使用技术:html2canvas插件 + jspdf插件

实现思路:1)将h5页面用canvas画成图片

2)利用jspdf将图片插入pdf文件并下载

缺点:生成的pdf是由图片拼接而成的,不能实现复制

实现版本:

第一版:将h5页面转成一张长图,再根据A4值的高度将长图截成多个页面

缺点:使用起来不灵活。没办法在每个页面上插入页眉页脚

实现代码:

1)weixin项目的  pdftemplate.vue文件

(由于是内嵌微信项目,所以在微信项目页面能操作dom)

<template><view v-if="calData" ref="refContent">.......</view>
</template>
import { downloadPdf } from '@/common/utils/insPdfUtil' //实现转换的页面
export default {......mounted(){if (this.calData && this.calData.userInfo && this.calData.userInfo.name) {this.htmlTitle = this.calData.userInfo.name + '的计划书'}//this.$refs.refContent.$el:需要转化的页面内容//this.htmlTitle:文件名downloadPdf(this.$refs.refContent.$el, this.htmlTitle)}
}

2)insPdfUtil.js文件

import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'/*** 创建并下载pdf* @param {HTMLElement} targetDom dom元素* @param {String} title pdf保存名字* @param {function} callback 回调函数*/
const downloadPdf = (targetDom, title, callback) => {html2canvas(targetDom, {useCORS: true}).then(function(canvas) {const contentWidth = canvas.widthconst contentHeight = canvas.heightconst pageHeight = (contentWidth / 592.28) * 841.89let leftHeight = contentHeightlet position = 0const imgWidth = 595.28const imgHeight = (592.28 / contentWidth) * contentHeightconst pageData = canvas.toDataURL('image/jpeg', 1.0)const PDF = new JsPDF('', 'pt', 'a4')if (leftHeight < pageHeight) {PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)} else {while (leftHeight > 0) {PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)leftHeight -= pageHeightposition -= 841.89if (leftHeight > 0) {PDF.addPage() //添加pdf页树}}}PDF.save(title + '.pdf')  //pdf下载if (typeof callback === 'function') {callback()}})
}export { downloadPdf }

第二版:在h5页面上先设置好每一页要显示的数据存为对象传给insPdfUtil页面遍历生成PDF

缺点:移动设备部分下载失败

知识点:html2canvas插件可以绘制$el虚拟dom,也可直接传真实DOM(注:需要注册到页面上,可以在页面上定义一个div占位,在操作dom元素将元素插入该位置)

实现代码:

1)weixin项目的   pdftemplate.vue文件

1、使用ref获取虚拟dom的方式
2、使用操作dom的方式
3、动态生成dom,必须要挂载到页面上,可以先在页面写一个占位的标签
<template><view v-if="calData"><!-- 使用ref获取虚拟dom的方式 --><view ref="topHead"> ... </view><!-- 使用操作dom的方式 --><view class="topBody"> ... </view><!-- 动态生成dom,必须要挂载到页面上,可以先在页面写一个占位的标签 --><view class="perch"> ... </view>.......</view>
</template>
import { downloadPdf } from '@/common/utils/insPdfUtil' //实现转换的页面
export default {......//--定义为数组遍历data(){refList: []}mounted(){if (this.calData && this.calData.userInfo && this.calData.userInfo.name) {this.htmlTitle = this.calData.userInfo.name + '的计划书'}//this.$refs.refContent.$el:需要转化的页面内容//this.htmlTitle:文件名this.refList.push(this.$refs.refContent.$el)let topBody = document.queryselect('.topBody')this.refList.push(topBody)//--动态生成dom,必须要挂载到页面上,可以先在页面写一个占位的标签let div = document.createElement("div")div.innerHtml = '动态生成的div'let perch = document.createElement("perch").appendChild(div)this.refList.push(div)downloadPdf(this.refList, this.htmlTitle, () => {回调函数})}
}

2)insPdfUtil.js文件

import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'/*** 创建并下载pdf* html2canvas画是异步画图,所以这里需要用到promise.all* @param {HTMLElement} targetDom dom元素* @param {String} title pdf保存名字* @param {function} callback 回调函数*/
const downloadPdf = (targetList, title, callback) => {var pdf = new JsPDF('', 'pt', 'a4', true)const promiseList = []targetList.forEach((item) => {promiseList.push(html2canvas(item, {useCORS: true,scale: 1}))})Promise.all(promiseList).then((resList) => {resList.forEach((item, index) => {var contentWidth = item.widthvar contentHeight = item.height// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高var imgWidth = 595.28var imgHeight = (592.28 / contentWidth) * contentHeightvar pageData = item.toDataURL('', 1)pdf.addImage(pageData, 'JPEG', 0, 10, imgWidth, imgHeight)if (index < resList.length - 1) {pdf.addPage()}if (index === resList.length - 1) {PDF.save(title + '.pdf')  //pdf下载if (typeof callback === 'function') {callback()}}})})
}export { downloadPdf }

第三版:利用调后端上传文件的接口生成下载链接,PDF下载更改为a标签下载的方式

缺点:没有解决IOS下载失败的问题

实现代码:insPdfUtil.js文件

import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'
//调接口
import constant from '@/common/constant'
import store from '@/store'/*** 创建并下载pdf* html2canvas画是异步画图,所以这里需要用到promise.all* @param {HTMLElement} targetDom dom元素* @param {String} title pdf保存名字* @param {function} callback 回调函数*/
const downloadPdf = (targetList, title, callback) => {var pdf = new JsPDF('', 'pt', 'a4', true)const promiseList = []targetList.forEach((item) => {promiseList.push(html2canvas(item, {useCORS: true,scale: 1}))})Promise.all(promiseList).then((resList) => {resList.forEach((item, index) => {var contentWidth = item.widthvar contentHeight = item.height// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高var imgWidth = 595.28var imgHeight = (592.28 / contentWidth) * contentHeightvar pageData = item.toDataURL('', 1)pdf.addImage(pageData, 'JPEG', 0, 10, imgWidth, imgHeight)if (index < resList.length - 1) {pdf.addPage()}if (index === resList.length - 1) {const file = pdf.output('blob')// 这样子后台就有名字了const fileObject = new File([file], title + '.pdf', { type: 'application/pdf' })uploadFileXHR(fileObject, (downloadUrl) => {// 利用a标签的download属性下载pdf,IOS不适用const a = document.createElement('a')a.setAttribute('href', downloadUrl)a.download = title + '.pdf'a.click()if (typeof callback === 'function') {callback()}})}})})
}// --调后端接口的代码
const uploadFileXHR = (file, successUpload) => {const uploadUrl = `${constant.reqBaseUrl}/ins/file/tenantUploadFile`const data = {tenant: 'AKIAIOSFODNN7EXAMPLE',fileType: '5e25920b5b5b11e9bf97080027e99028',bucketName: 'papers'}const header = {token: store.getters.token}const formData = new FormData()for (const keys in data) {formData.append(keys, data[keys])}formData.append('upload', file)const xhr = new XMLHttpRequest()xhr.open('POST', uploadUrl, true)for (const keys in header) {xhr.setRequestHeader(keys, header[keys])}xhr.onreadystatechange = (ev) => {if (xhr.readyState === 4) {if (xhr.status === 200) {const data = JSON.parse(xhr.responseText)if (data.resCode === '0') {successUpload(data.data.preview_url)}} else {//}}}xhr.send(formData)
}export { downloadPdf }

第四版:将后端生成的pdf文件地址通过webview通信传回APP,利用uniapp的uni.downloadFile和uni.saveFile下载文件

实现代码:1) insPdfUtil.js文件

.....
// 封装的webview通信代码
import { postmessageJumpOnApp } from '@/common/utils/insWebviewUtil'
.....if (index === resList.length - 1) {const file = pdf.output('blob')// 这样子后台就有名字了const fileObject = new File([file], title + '.pdf', { type: 'application/pdf' })uploadFileXHR(fileObject, (downloadUrl) => {/* const a = document.createElement('a')a.setAttribute('href', downloadUrl)a.download = title + '.pdf'a.click() */// ----------------postmessageJumpOnApp(downloadUrl)if (typeof callback === 'function') {callback()}})
}.....

2) app项目页面 pdfpages.vue

<template><view v-if="src"><view v-if="!pageData.customerVisible && show"><web-view :src="src" @message="message" /><!--  --></view></view>.......
</template><script>
......
methods: {message(e) {if (e &&e.detail && e.detail.data &&e.detail.data.length &&e.detail.data[0].jumpTo) {// 接受到weixin项目传过来的pdf文件地址uni.downloadFile({url: e.detail.data[0].jumpTo,success: (res) => {if (res.statusCode === 200) {var filePath = res.tempFilePath;uni.saveFile({tempFilePath: filePath,success: function (res) {var savedFilePath = res.savedFilePath;uni.showToast({icon:'none',mask:true,title:'文件已保存并即将打开',duration:1000})setTimeout(()=>{uni.openDocument({filePath: savedFilePath,success: function (res) {console.log('打开文档成功');}});},1000)},fail:(err)=>{uni.showToast({icon:'none',mask:true,title:'文件下载失败',duration:1000})}});}}})return}},
}
......</script>

h5页面转PDF下载(包括pc端和移动端)相关推荐

  1. VUE页面转pdf下载

    一.欢迎你们走进杭老师小学堂,今天给大家讲解一下vue页面转PDF下载,本人亲测有效哦! 随着项目体积的不断增加,我们的项目内容也逐渐越来越丰富新颖! 多了不说上需求跟代码! 1.首先我们要绑定一个按 ...

  2. vue pdf下载及预览(移动端)

    本文使用的是 vue-pdf,其实还有其他的很多比如pdf.js,只不过觉得这个和vue结合了应该不用下载一堆东西,直接npm install就可以,所以采用vue-pdf来撰写pdf下载及预览. 无 ...

  3. H5页面video强制下载,不打开新页面播放

    移动端H5页面video标签,点击按钮下载当前资源 1. 点击下载后ios浏览器页能直接下载,不会打开新页面播放视频. 2. 视频改名. 3. 下载进度显示,不能空屏或者无操作反馈 实现方式思考: 使 ...

  4. h5页面添加APP下载引导页实现APP下载

    最近呢,接到一个新需求,在我们负责的H5网页网站添加一个app下载引导页,成功之后来给大家分享一下! 先给大家来看一下ios跟Android微信内点击链接有什么不同: Android展示显示微信内空白 ...

  5. 微信公众号开发+H5页面语音录入+下载+amr转换为MP3+讯飞语音转文字

    其实作为H5想要做语音识别,自认为还说有各种弊端得,同时还是微信公众号里面,如果小程序得话,或许会简单一点,但是这里是在公众号里面开发,在这个过程中查阅个各种资料,其实里面得东西都大同小异,但是大多数 ...

  6. vue实现移动端H5页面截图

    vue实现移动端H5页面截图 1.vue使用html2canvas实现移动端H5页面截图并下载. 2.html2canvas能够实现在用户浏览器端直接对整个或部分页面进行截屏.这个html2canva ...

  7. h5页面移动端的社会化分享_Adobe年尾续运H5页面

    好看的H5层出不穷 小编的压力越来越大 头发变得越来越稀少 但这都不是重点 重点是 我们应该怎么学会操作和应用呢 1. H5页面是什么 首先,H5这个词,来自"HTML5",且是国 ...

  8. 移动端 H5页面适配

    一.基础概念 在了解如何做H5页面适配前,大家都应该把移动端涉及的一些概念搞明白,比如:dpr 是什么意思? 移动端H5解惑-概念术语(一) 二.为什么要做页面适配 2.1 PC端为什么要解决浏览器兼 ...

  9. 移动端开发——APP端上H5容器化建设

    1. 背景 当前移动端和前端的结合愈加紧密,尤其是在偏重活动运营的电商App中,受制于App版本审核,具备研发成本低.可灵活发布等特点的H5页面受到青睐,使其在APP端上承接了越来越多的业务.然而H5 ...

最新文章

  1. tcp 测试工具_6款免费网络延迟测试工具
  2. PHP 缓存插件之 Zend Opcache ( 取代 APC )
  3. JAVA实现数值的整数次方(《剑指offern》)
  4. ab753变频器参数怎么拷贝到面板_技术贴:100吨连铸安川变频器的更换
  5. 动图:程序员才懂的这些!
  6. Java枚举(用Java普通类模拟枚举的实现原理及JDK枚举API使用示例)
  7. docker entrypoint入口文件详解
  8. c++ 显示三维散点图_【无机纳米材料科研制图——OriginLab 0209】Origin散点图线性拟合与非线性拟合...
  9. 使用异步任务加载网络上的图片
  10. 03、三种简单的计时器
  11. lr 远程压力机部署安装
  12. 在阿里云上创建带gpu的ecs实例
  13. 长安链技术架构与共识模块介绍
  14. 短视频技术与市场动态
  15. HD TUNE以及所有其他硬盘检测工具都不能使用的情况
  16. 基于SSM毕业生就业管理系统
  17. 盘古石杯电子取证比赛WP
  18. 商用计算机使用温度,电脑一般的使用温度为?
  19. #1024程序员节#活动勋章获取方式
  20. int a[]与int* a的区别

热门文章

  1. 旅游网站管理系统简易版 php开源,基于Laravel框架开发的旅游网站管理系统PHP源码...
  2. JavaScript高级特效
  3. Mac 卸载 隐蔽软件 Core_Sync 的步骤
  4. linux在线安装libxml2,关于linux 安装libxml2
  5. putty修改显示服务器ip或域名,putty 标题显示ip
  6. LBR_iiwa_14_R820代码解析
  7. DTAS3D 三维公差分析与尺寸链计算软件-AI自动建模案例
  8. jeesite4中图片上传功能
  9. 什么是DCDC电源电涌,来源是哪里
  10. InVEST模型 | HAbitat quality模块计算生境质量