【JS】前端导出 pdf 并且压缩 zip

前端导出 pdf 并且压缩 zip

阿星发布于 51 分钟前

需求

原理

用到的插件

html2canvas

jspdf

jszip

file-saver

模板

<template>

<div class="table-class">

<div class="name-style">{{ row.meetingName }}会议纪要</div>

<table border="0" class="table-style">

<tbody>

<tr>

<td>会议主题</td>

<td colspan="5">{{ row.meetingTheme }}</td>

</tr>

<tr>

<td>会议时间</td>

<td>{{ meetingTime || '-' }}</td>

<td>会议地点</td>

<td>{{ row.meetingPlace }}</td>

<td>会议级别</td>

<td>{{ matterLevelObj[row.meetingLevel]||"-" }}</td>

</tr>

<tr>

<td>主持人</td>

<td>{{ row.host }}</td>

<td>记录人</td>

<td>{{ row.recorder }}</td>

<td>抄报</td>

<td>{{ row.ccleader }}</td>

</tr>

<tr>

<td>审批人</td>

<td colspan="5">{{ row.approverName || '-' }}</td>

</tr>

<tr>

<td>参与人</td>

<td colspan="5">{{ row.participant }}</td>

</tr>

<tr>

<td>备注</td>

<td colspan="5">{{ row.remark }}</td>

</tr>

<tr>

<td colspan="6" class="td-bg">会议内容</td>

</tr>

<tr>

<td colspan="6">{{ row.remark }}</td>

</tr>

<tr>

<td colspan="6" class="td-bg">会议事项</td>

</tr>

<tr>

<td>序号</td>

<td>类型</td>

<td>工作事项</td>

<td>负责人</td>

<td>预计完成时间</td>

<td>工作计划</td>

</tr>

<tr v-for="(item,i) of row.meetMatters" :key="i">

<td>{{ i+1 }}</td>

<td>{{ item.type }}</td>

<td>{{ item.workItem }}</td>

<td>{{ item.principalName }}</td>

<td>{{ item.planEndtime }}</td>

<td>{{ item.workPlan }}</td>

</tr>

</tbody>

</table>

</div>

</template>

<script>

import mixin from '../mixin';

export default {

name: 'ExportPdf',

mixins: [mixin],

props: {

row: {

type: Object,

default: () => {},

},

},

computed: {

meetingTime() {

const start = this.row?.meetingStartTime;

const end = this.row?.meetingEndTime;

if (start && end) {

return start.substr(0, start.length - 3) + '~' + end.substr(0, end.length - 3);

} else {

return '';

}

},

},

};

</script>

<style lang="scss" scoped>

.table-class {

background-color: #fff;

width: 1000px;

margin: auto;

padding: 40px;

box-sizing: border-box;

.name-style {

text-align: center;

font-size: 20px;

font-weight: bold;

margin-bottom: 20px;

}

}

.table-style {

border-collapse: collapse;

width: 100%;

text-align: center;

td,

th {

padding: 10px;

font-size: 15px;

border: 1px solid black;

}

.td-bg {

background: #ccc;

}

}

</style>

异步导出函数

async exportMeeting (type) {

// type:'1' 选择导出 'all':导出所有

try {

this.allLoading = true

let selectedData = []

if (type === '1') {

const ids = this.multipleSelection.map(el => el.id)

selectedData = await this.getMeetingAll(ids)

} else if (type === 'all') {

selectedData = await this.getMeetingAll()

}

this.loadingText = '正在拼命导出...'

const zip = new JSZip()

const promises = []

this.isShowPdf = true

for (let i = 0; i < selectedData.length; i++) {

const element = selectedData[i]

this.data = element

// 等待每一个转为pdf

const p = await htmlToPdf.getPdf(document.getElementById('pdf'), element.meetingName)

promises.push(p)

}

// 等到所有的promise执行完成依次压缩到zip中

Promise.all(promises).then(async (pdfs) => {

for (let i = 0; i < pdfs.length; i++) {

const { PDF, name } = pdfs[i]

// 如果只是导出一个pdf,则导出pdf格式

if (pdfs.length === 1) {

PDF.save(`${name}-${new Date().getTime()}.pdf`)

this.allLoading = false

this.loadingText = '正在请求数据'

} else {

// 否则添加到压缩包里面

await zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob'))

}

}

if (pdfs.length > 1) {

zip.generateAsync({ type: 'blob' }).then(content => {

FileSaver.saveAs(content, '销项管理平台会议纪要.zip')

})

}

}).finally(() => {

this.allLoading = false

this.loadingText = '正在请求数据'

})

} catch (e) {

this.allLoading = false

this.loadingText = '正在请求数据'

throw new Error(e)

}

},

获取 pdf 的公共封装函数

// 导出pdf

import html2Canvas from 'html2canvas';

import JsPDF from 'jspdf';

export default {

getPdf: (el, pdfName) => {

// 滚轮滑动造成的,主要是html2canvas是根据body进行截图,若内容高度高于body时,就会出现这样的问题

// 解决方案:(在生成截图前,先把滚动条置顶)

window.pageYoffset = 0;

document.documentElement.scrollTop = 0;

document.body.scrollTop = 0;

return new Promise((resolve, reject) => {

// 在点击保存图片时,此时要保存的资源较多,造成模块并没有完全加载完毕,就已经生成了截图。

// 解决方案:(延迟)

setTimeout(() => {

// 这句挺重要

html2Canvas(el, {

scale: 4,

dpi: 300,

useCORS: true,

// allowTaint: true

})

.then((canvas) => {

const contentWidth = canvas.width;

const contentHeight = canvas.height;

const pageHeight = (contentWidth / 592.28) * 841.89;

let leftHeight = contentHeight; //

let position = 0;

const imgWidth = 595.28;

const imgHeight = (592.28 / contentWidth) * contentHeight;

const pageData = canvas.toDataURL('image/jpeg', 1.0);

const PDF = new JsPDF('', 'pt', 'a4');

if (leftHeight < pageHeight) {

// 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;

PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);

// pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);

} else {

// 分页

while (leftHeight > 0) {

PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);

leftHeight -= pageHeight;

position -= 841.89;

// 避免添加空白页

if (leftHeight > 0) {

PDF.addPage();

}

}

}

resolve({ PDF, name: pdfName });

})

.catch((e) => {

reject(e);

});

}, 500);

});

},

};

遇到的问题

  • 添加到 zip 时,获取 pdf 的内容

zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //第二个参数PDF.output('blob')

  • 添加到 zip 时,同名文件会被覆盖

// 通过给文件名添加一个时间戳解决

zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //`${name}-${new Date().getTime()}.pdf`

javascriptvue.js

阅读 26更新于 48 分钟前

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

阿星

这个人不懒,但不知道写啥

45 声望

4 粉丝

0 条评论

得票时间

avatar

阿星

这个人不懒,但不知道写啥

45 声望

4 粉丝

宣传栏

需求

原理

用到的插件

html2canvas

jspdf

jszip

file-saver

模板

<template>

<div class="table-class">

<div class="name-style">{{ row.meetingName }}会议纪要</div>

<table border="0" class="table-style">

<tbody>

<tr>

<td>会议主题</td>

<td colspan="5">{{ row.meetingTheme }}</td>

</tr>

<tr>

<td>会议时间</td>

<td>{{ meetingTime || '-' }}</td>

<td>会议地点</td>

<td>{{ row.meetingPlace }}</td>

<td>会议级别</td>

<td>{{ matterLevelObj[row.meetingLevel]||"-" }}</td>

</tr>

<tr>

<td>主持人</td>

<td>{{ row.host }}</td>

<td>记录人</td>

<td>{{ row.recorder }}</td>

<td>抄报</td>

<td>{{ row.ccleader }}</td>

</tr>

<tr>

<td>审批人</td>

<td colspan="5">{{ row.approverName || '-' }}</td>

</tr>

<tr>

<td>参与人</td>

<td colspan="5">{{ row.participant }}</td>

</tr>

<tr>

<td>备注</td>

<td colspan="5">{{ row.remark }}</td>

</tr>

<tr>

<td colspan="6" class="td-bg">会议内容</td>

</tr>

<tr>

<td colspan="6">{{ row.remark }}</td>

</tr>

<tr>

<td colspan="6" class="td-bg">会议事项</td>

</tr>

<tr>

<td>序号</td>

<td>类型</td>

<td>工作事项</td>

<td>负责人</td>

<td>预计完成时间</td>

<td>工作计划</td>

</tr>

<tr v-for="(item,i) of row.meetMatters" :key="i">

<td>{{ i+1 }}</td>

<td>{{ item.type }}</td>

<td>{{ item.workItem }}</td>

<td>{{ item.principalName }}</td>

<td>{{ item.planEndtime }}</td>

<td>{{ item.workPlan }}</td>

</tr>

</tbody>

</table>

</div>

</template>

<script>

import mixin from '../mixin';

export default {

name: 'ExportPdf',

mixins: [mixin],

props: {

row: {

type: Object,

default: () => {},

},

},

computed: {

meetingTime() {

const start = this.row?.meetingStartTime;

const end = this.row?.meetingEndTime;

if (start && end) {

return start.substr(0, start.length - 3) + '~' + end.substr(0, end.length - 3);

} else {

return '';

}

},

},

};

</script>

<style lang="scss" scoped>

.table-class {

background-color: #fff;

width: 1000px;

margin: auto;

padding: 40px;

box-sizing: border-box;

.name-style {

text-align: center;

font-size: 20px;

font-weight: bold;

margin-bottom: 20px;

}

}

.table-style {

border-collapse: collapse;

width: 100%;

text-align: center;

td,

th {

padding: 10px;

font-size: 15px;

border: 1px solid black;

}

.td-bg {

background: #ccc;

}

}

</style>

异步导出函数

async exportMeeting (type) {

// type:'1' 选择导出 'all':导出所有

try {

this.allLoading = true

let selectedData = []

if (type === '1') {

const ids = this.multipleSelection.map(el => el.id)

selectedData = await this.getMeetingAll(ids)

} else if (type === 'all') {

selectedData = await this.getMeetingAll()

}

this.loadingText = '正在拼命导出...'

const zip = new JSZip()

const promises = []

this.isShowPdf = true

for (let i = 0; i < selectedData.length; i++) {

const element = selectedData[i]

this.data = element

// 等待每一个转为pdf

const p = await htmlToPdf.getPdf(document.getElementById('pdf'), element.meetingName)

promises.push(p)

}

// 等到所有的promise执行完成依次压缩到zip中

Promise.all(promises).then(async (pdfs) => {

for (let i = 0; i < pdfs.length; i++) {

const { PDF, name } = pdfs[i]

// 如果只是导出一个pdf,则导出pdf格式

if (pdfs.length === 1) {

PDF.save(`${name}-${new Date().getTime()}.pdf`)

this.allLoading = false

this.loadingText = '正在请求数据'

} else {

// 否则添加到压缩包里面

await zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob'))

}

}

if (pdfs.length > 1) {

zip.generateAsync({ type: 'blob' }).then(content => {

FileSaver.saveAs(content, '销项管理平台会议纪要.zip')

})

}

}).finally(() => {

this.allLoading = false

this.loadingText = '正在请求数据'

})

} catch (e) {

this.allLoading = false

this.loadingText = '正在请求数据'

throw new Error(e)

}

},

获取 pdf 的公共封装函数

// 导出pdf

import html2Canvas from 'html2canvas';

import JsPDF from 'jspdf';

export default {

getPdf: (el, pdfName) => {

// 滚轮滑动造成的,主要是html2canvas是根据body进行截图,若内容高度高于body时,就会出现这样的问题

// 解决方案:(在生成截图前,先把滚动条置顶)

window.pageYoffset = 0;

document.documentElement.scrollTop = 0;

document.body.scrollTop = 0;

return new Promise((resolve, reject) => {

// 在点击保存图片时,此时要保存的资源较多,造成模块并没有完全加载完毕,就已经生成了截图。

// 解决方案:(延迟)

setTimeout(() => {

// 这句挺重要

html2Canvas(el, {

scale: 4,

dpi: 300,

useCORS: true,

// allowTaint: true

})

.then((canvas) => {

const contentWidth = canvas.width;

const contentHeight = canvas.height;

const pageHeight = (contentWidth / 592.28) * 841.89;

let leftHeight = contentHeight; //

let position = 0;

const imgWidth = 595.28;

const imgHeight = (592.28 / contentWidth) * contentHeight;

const pageData = canvas.toDataURL('image/jpeg', 1.0);

const PDF = new JsPDF('', 'pt', 'a4');

if (leftHeight < pageHeight) {

// 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;

PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);

// pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);

} else {

// 分页

while (leftHeight > 0) {

PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);

leftHeight -= pageHeight;

position -= 841.89;

// 避免添加空白页

if (leftHeight > 0) {

PDF.addPage();

}

}

}

resolve({ PDF, name: pdfName });

})

.catch((e) => {

reject(e);

});

}, 500);

});

},

};

遇到的问题

  • 添加到 zip 时,获取 pdf 的内容

zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //第二个参数PDF.output('blob')

  • 添加到 zip 时,同名文件会被覆盖

// 通过给文件名添加一个时间戳解决

zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //`${name}-${new Date().getTime()}.pdf`

以上是 【JS】前端导出 pdf 并且压缩 zip 的全部内容, 来源链接: www.h5w3.com/114038.html

回到顶部