前端页面导出PPT(Vue3)
2023-11-08 15:10 WEB前端小菜鸟 阅读(914) 评论(0) 编辑 收藏 举报问题1:如在首页点击导出把 首页的echarts图作为一个页面导出,然后导出PPT里面还包含其他页面的东西(其他页面的图标 我都获取不到DOM如何截图插入PPT),
解决方案:把其他页面也写在首页,这样不就能获取到DOM了吗 然后把其他页面fixed z-inde:-9999不就ok了吗
问题2:导出PPT的时候太慢太卡 ,客户会误以为死机了,加loading也要等很久才出来loading
核心:就是每一页ppt都单独写成一个页面,然后汇总到一起,每一个页面先获取DOM截图生成base64图片,然后在用ppt插件把每一页图片插进去然后导出搞定
PPT默认比例是16:9我,16除以9==1.77
我的方案是页面写死宽高1920*1080布局1920除以1080 ==1.77 ;
最终方案我用1920*1080布局,导出的图片的w h 都写成100%,这样就能铺满PPT了,每个ppt页面都叫UI出图
然后每一页PPT看做一个DOM,我用的vue3,so绑定的是ref
把每一页PPT当成一个页面,然后获取到每个月页面的DOM,然后把他弄成base64的图片,最后在插入到PPT里面导出
<!-- PPT相关的所有东西 --> <div ref="ppt" class="ppt-all"> <ppt1 ref="page1Ref"></ppt1> <ppt2 ref="page2Ref"></ppt2> <ppt3 :dataAll="dataAll.dataAll" ref="page3Ref"></ppt3> <ppt4 v-if="dataAll.dataAll" :dataAll="dataAll.dataAll" ref="page4Ref"></ppt4> <ppt5 :dataAll="dataAll.dataAll" ref="page5Ref"></ppt5> <ppt6 :dataAll="dataAll.dataAll" ref="page6Ref"></ppt6> <ppt7 ref="page7Ref"></ppt7>
... </div>
下面是等所有页面都拿到自己页面的base64图片后再调用 插入PPT的方法,如下第一种注释写法 loadding要很久才回出来,那时PPT也导出,第二种loading实时出来
const exportPPt = async () => {
const loading = ElLoading.service({
lock: true,
text: "导出中",
background: "rgba(0, 0, 0, 0.7)",
});
// await Promise.all([getBase64Result(1, page1Ref.value.page1Ref),
// getBase64Result(2, page2Ref.value.page2Ref),
// getBase64Result(3, page3Ref.value.page3Ref),
// getBase64Result(4, page4Ref.value.page4Ref),
// getBase64Result(5, page5Ref.value.page5Ref),
// getBase64Result(6, page6Ref.value.page6Ref),
// getBase64Result(7, page7Ref.value.page7Ref),
// getBase64Result(8, page8Ref.value.page8Ref),
// getBase64Result(9, page9Ref.value.page9Ref),
// getBase64Result(10, page10Ref.value.page10Ref),
// getBase64Result(11, page11Ref.value.page11Ref),
// getBase64Result(12, page12Ref.value.page12Ref),
// getBase64Result(13, page13Ref.value.page13Ref),
// getBase64Result(14, page14Ref.value.page14Ref),
// getBase64Result(15, page15Ref.value.page15Ref),
// getBase64Result(16, page16Ref.value.page16Ref),
// getBase64Result(17, page17Ref.value.page17Ref),
// getBase64Result(18, page18Ref.value.page18Ref),
// getBase64Result(19, page19Ref.value.page19Ref),
// getBase64Result(20, page20Ref.value.page20Ref),
// getBase64Result(21, page21Ref.value.page21Ref),
// getBase64Result(22, page22Ref.value.page22Ref),
// getBase64Result(23, page23Ref.value.page23Ref),
// getBase64Result(24, page24Ref.value.page24Ref),
// getBase64Result(25, page25Ref.value.page25Ref)])
await getBase64Result(1, page1Ref.value.page1Ref);
await getBase64Result(2, page2Ref.value.page2Ref);
await getBase64Result(3, page3Ref.value.page3Ref);
await getBase64Result(4, page4Ref.value.page4Ref);
await getBase64Result(5, page5Ref.value.page5Ref);
await getBase64Result(6, page6Ref.value.page6Ref);
await getBase64Result(7, page7Ref.value.page7Ref);
await getBase64Result(8, page8Ref.value.page8Ref);
await getBase64Result(9, page9Ref.value.page9Ref);
await getBase64Result(10, page10Ref.value.page10Ref);
await getBase64Result(11, page11Ref.value.page11Ref);
await getBase64Result(12, page12Ref.value.page12Ref);
await getBase64Result(13, page13Ref.value.page13Ref);
await getBase64Result(14, page14Ref.value.page14Ref);
await getBase64Result(15, page15Ref.value.page15Ref);
await getBase64Result(16, page16Ref.value.page16Ref);
await getBase64Result(17, page17Ref.value.page17Ref);
await getBase64Result(18, page18Ref.value.page18Ref);
await getBase64Result(19, page19Ref.value.page19Ref);
await getBase64Result(20, page20Ref.value.page20Ref);
await getBase64Result(21, page21Ref.value.page21Ref);
await getBase64Result(22, page22Ref.value.page22Ref);
await getBase64Result(23, page23Ref.value.page23Ref);
await getBase64Result(24, page24Ref.value.page24Ref);
await getBase64Result(25, page25Ref.value.page25Ref);
lastPPT();
loading.close();
};
这里就导出,先安装插件
npm install pptxgenjs --save // ppt插件
import html2canvas from "html2canvas"; //DOM转转图片
const generateImage = (dom: any) => { return new Promise((resolve) => { html2canvas(dom).then((canvas) => { const base64img = canvas.toDataURL("image/png", 1.0); //转base64图片 resolve(base64img); }); }); };
import pptxgen from "pptxgenjs";
const lastPPT = () => { // 1. 创建PPT let ppt = new pptxgen(); // ppt.layout = 'LAYOUT_WIDE'; //13.5 x 7.5 // 2. 创建一个PPT页面,每调用一次 ppt.addSlide() 都可以生成一张新的页面 // 建议把每个页面的构造抽成一个个函数,然后通过函数调用生成新页面,代码不会很乱 let slide = ppt.addSlide(); // 图片铺满的配置 const optionsImage = { x: 0, y: 0, h: "100%", w: "100%", sizing: { type: "contain" }, // 图片尺寸 }; slide.addImage({ ...optionsImage, data: page1Image.value, // 我用的是二进制图片 }); //第二个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page2Image.value, // 我用的是二进制图片 }); //第3个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page3Image.value, // 我用的是二进制图片 }); ... //第25个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page25Image.value, // 我用的是二进制图片 }); // 4. 生成PPT, 括号中的fileName,就是生成的 PPT名字,可以使用 .then 或者 .catch处理对应事件。 ppt.writeFile({ fileName: "PPT的名字.pptx" }); };
贴一个项目中的代码吧哈哈
<template> <!-- <el-button class="export-btn" type="primary" @click="exportPPt">导出</el-button> --> <!-- PPT相关的所有东西 --> <div ref="ppt" class="ppt-all"> <ppt1 ref="page1Ref"></ppt1> <ppt2 ref="page2Ref"></ppt2> <ppt3 :dataAll="dataAll.dataAll" ref="page3Ref"></ppt3> <ppt4 v-if="dataAll.dataAll" :dataAll="dataAll.dataAll" ref="page4Ref"></ppt4> <ppt5 :dataAll="dataAll.dataAll" ref="page5Ref"></ppt5> <ppt6 :dataAll="dataAll.dataAll" ref="page6Ref"></ppt6> <ppt7 ref="page7Ref"></ppt7> <ppt8 :dataAll="dataAll.dataAll" ref="page8Ref"></ppt8> <ppt9 :dataAll="dataAll.dataAll" ref="page9Ref"></ppt9> <ppt10 :dataAll="dataAll.dataAll" ref="page10Ref"></ppt10> <ppt11 :dataAll="dataAll.dataAll" ref="page11Ref"></ppt11> <ppt12 v-if="dataAll.dataAll" :dataAll="dataAll.dataAll" ref="page12Ref"></ppt12> <ppt13 :dataAll="dataAll.dataAll" ref="page13Ref"></ppt13> <ppt14 :dataAll="dataAll.dataAll" ref="page14Ref"></ppt14> <ppt15 :dataAll="dataAll.dataAll" ref="page15Ref"></ppt15> <ppt16 :dataAll="dataAll.dataAll" ref="page16Ref"></ppt16> <ppt17 :dataAll="dataAll.dataAll" ref="page17Ref"></ppt17> <ppt18 :dataAll="dataAll.dataAll" ref="page18Ref"></ppt18> <ppt19 :dataAll="dataAll.dataAll" ref="page19Ref"></ppt19> <ppt20 v-if="dataAll.dataAll" :dataAll="dataAll.dataAll" ref="page20Ref"></ppt20> <ppt21 :dataAll="dataAll.dataAll" ref="page21Ref"></ppt21> <ppt22 :dataAll="dataAll.dataAll" ref="page22Ref"></ppt22> <ppt23 ref="page23Ref"></ppt23> <ppt24 :dataAll="dataAll.dataAll" ref="page24Ref"></ppt24> <ppt25 ref="page25Ref"></ppt25> <ppt26 ref="page26Ref"></ppt26> </div> </template> <script lang="ts" setup> import { defineExpose, ref, reactive,defineEmits } from "vue"; import { ElLoading } from "element-plus"; import request from "@/API/request"; import serviceModule from "@/API/login"; import { ElMessage } from "element-plus"; import ppt1 from "./ppt1.vue"; import ppt2 from "./ppt2.vue"; import ppt3 from "./ppt3.vue"; import ppt4 from "./ppt4.vue"; import ppt5 from "./ppt5.vue"; import ppt6 from "./ppt6.vue"; import ppt7 from "./ppt7.vue"; import ppt8 from "./ppt8.vue"; import ppt9 from "./ppt9.vue"; import ppt10 from "./ppt10.vue"; import ppt11 from "./ppt11.vue"; import ppt12 from "./ppt12.vue"; import ppt13 from "./ppt13.vue"; import ppt14 from "./ppt14.vue"; import ppt15 from "./ppt15.vue"; import ppt16 from "./ppt16.vue"; import ppt17 from "./ppt17.vue"; import ppt18 from "./ppt18.vue"; import ppt19 from "./ppt19.vue"; import ppt20 from "./ppt20.vue"; import ppt21 from "./ppt21.vue"; import ppt22 from "./ppt22.vue"; import ppt23 from "./ppt23.vue"; import ppt24 from "./ppt24.vue"; import ppt25 from "./ppt25.vue"; import ppt26 from "./ppt26.vue"; import pptxgen from "pptxgenjs"; import html2canvas from "html2canvas"; const ppt = ref(null); const page1Ref = ref(null); const page1Image = ref(""); const page2Ref = ref(null); const page2Image = ref(""); const page3Ref = ref(null); const page3Image = ref(""); const page4Ref = ref(null); const page4Image = ref(""); const page5Ref = ref(null); const page5Image = ref(""); const page6Ref = ref(null); const page6Image = ref(""); const page7Ref = ref(null); const page7Image = ref(""); const page8Ref = ref(null); const page8Image = ref(""); const page9Ref = ref(null); const page9Image = ref(""); const page10Ref = ref(null); const page10Image = ref(""); const page11Ref = ref(null); const page11Image = ref(""); const page12Ref = ref(null); const page12Image = ref(""); const page13Ref = ref(null); const page13Image = ref(""); const page14Ref = ref(null); const page14Image = ref(""); const page15Ref = ref(null); const page15Image = ref(""); const page16Ref = ref(null); const page16Image = ref(""); const page17Ref = ref(null); const page17Image = ref(""); const page18Ref = ref(null); const page18Image = ref(""); const page19Ref = ref(null); const page19Image = ref(""); const page20Ref = ref(null); const page20Image = ref(""); const page21Ref = ref(null); const page21Image = ref(""); const page22Ref = ref(null); const page22Image = ref(""); const page23Ref = ref(null); const page23Image = ref(""); const page24Ref = ref(null); const page24Image = ref(""); const page25Ref = ref(null); const page25Image = ref(""); const page26Ref = ref(null); const page26Image = ref(""); const emit = defineEmits(['handleDataAll']); const dataAll = reactive({ dataAll: {}, }); // 生成图片 const generateImage = (dom: any) => { return new Promise((resolve) => { html2canvas(dom).then((canvas) => { const base64img = canvas.toDataURL("image/png", 1.0); resolve(base64img); }); }); }; // 获取到结果 async function getBase64Result(val: number, dom) { if (val === 1) { page1Image.value = await generateImage(dom); } if (val === 2) { page2Image.value = await generateImage(dom); } if (val === 3) { page3Image.value = await generateImage(dom); } if (val === 4) { page4Image.value = await generateImage(dom); } if (val === 5) { page5Image.value = await generateImage(dom); } if (val === 6) { page6Image.value = await generateImage(dom); } if (val === 7) { page7Image.value = await generateImage(dom); } if (val === 8) { page8Image.value = await generateImage(dom); } if (val === 9) { page9Image.value = await generateImage(dom); } if (val === 10) { page10Image.value = await generateImage(dom); } if (val === 11) { page11Image.value = await generateImage(dom); } if (val === 12) { page12Image.value = await generateImage(dom); } if (val === 13) { page13Image.value = await generateImage(dom); } if (val === 14) { page14Image.value = await generateImage(dom); } if (val === 15) { page15Image.value = await generateImage(dom); } if (val === 16) { page16Image.value = await generateImage(dom); } if (val === 17) { page17Image.value = await generateImage(dom); } if (val === 18) { page18Image.value = await generateImage(dom); } if (val === 19) { page19Image.value = await generateImage(dom); } if (val === 20) { page20Image.value = await generateImage(dom); } if (val === 21) { page21Image.value = await generateImage(dom); } if (val === 22) { page22Image.value = await generateImage(dom); } if (val === 23) { page23Image.value = await generateImage(dom); } if (val === 24) { page24Image.value = await generateImage(dom); } if (val === 25) { page25Image.value = await generateImage(dom); } if (val === 26) { page26Image.value = await generateImage(dom); } } const exportPPt = async () => { const loading = ElLoading.service({ lock: true, text: "导出中", background: "rgba(0, 0, 0, 0.7)", }); // await Promise.all([getBase64Result(1, page1Ref.value.page1Ref), // getBase64Result(2, page2Ref.value.page2Ref), // getBase64Result(3, page3Ref.value.page3Ref), // getBase64Result(4, page4Ref.value.page4Ref), // getBase64Result(5, page5Ref.value.page5Ref), // getBase64Result(6, page6Ref.value.page6Ref), // getBase64Result(7, page7Ref.value.page7Ref), // getBase64Result(8, page8Ref.value.page8Ref), // getBase64Result(9, page9Ref.value.page9Ref), // getBase64Result(10, page10Ref.value.page10Ref), // getBase64Result(11, page11Ref.value.page11Ref), // getBase64Result(12, page12Ref.value.page12Ref), // getBase64Result(13, page13Ref.value.page13Ref), // getBase64Result(14, page14Ref.value.page14Ref), // getBase64Result(15, page15Ref.value.page15Ref), // getBase64Result(16, page16Ref.value.page16Ref), // getBase64Result(17, page17Ref.value.page17Ref), // getBase64Result(18, page18Ref.value.page18Ref), // getBase64Result(19, page19Ref.value.page19Ref), // getBase64Result(20, page20Ref.value.page20Ref), // getBase64Result(21, page21Ref.value.page21Ref), // getBase64Result(22, page22Ref.value.page22Ref), // getBase64Result(23, page23Ref.value.page23Ref), // getBase64Result(24, page24Ref.value.page24Ref), await getBase64Result(1, page1Ref.value.page1Ref); await getBase64Result(2, page2Ref.value.page2Ref); await getBase64Result(3, page3Ref.value.page3Ref); await getBase64Result(4, page4Ref.value.page4Ref); await getBase64Result(5, page5Ref.value.page5Ref); await getBase64Result(6, page6Ref.value.page6Ref); await getBase64Result(7, page7Ref.value.page7Ref); await getBase64Result(8, page8Ref.value.page8Ref); await getBase64Result(9, page9Ref.value.page9Ref); await getBase64Result(10, page10Ref.value.page10Ref); await getBase64Result(11, page11Ref.value.page11Ref); await getBase64Result(12, page12Ref.value.page12Ref); await getBase64Result(13, page13Ref.value.page13Ref); await getBase64Result(14, page14Ref.value.page14Ref); await getBase64Result(15, page15Ref.value.page15Ref); await getBase64Result(16, page16Ref.value.page16Ref); await getBase64Result(17, page17Ref.value.page17Ref); await getBase64Result(18, page18Ref.value.page18Ref); await getBase64Result(19, page19Ref.value.page19Ref); await getBase64Result(20, page20Ref.value.page20Ref); await getBase64Result(21, page21Ref.value.page21Ref); await getBase64Result(22, page22Ref.value.page22Ref); await getBase64Result(23, page23Ref.value.page23Ref); await getBase64Result(24, page24Ref.value.page24Ref); await getBase64Result(25, page25Ref.value.page25Ref); await getBase64Result(26, page26Ref.value.page26Ref); lastPPT(); loading.close(); }; const lastPPT = () => { // 1. 创建PPT let ppt = new pptxgen(); // ppt.layout = 'LAYOUT_WIDE'; //13.5 x 7.5 // 2. 创建一个PPT页面,每调用一次 ppt.addSlide() 都可以生成一张新的页面 // 建议把每个页面的构造抽成一个个函数,然后通过函数调用生成新页面,代码不会很乱 let slide = ppt.addSlide(); // 图片铺满的配置 const optionsImage = { x: 0, y: 0, h: "100%", w: "100%", sizing: { type: "contain" }, // 图片尺寸 }; slide.addImage({ ...optionsImage, data: page1Image.value, // 我用的是二进制图片 }); //第二个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page2Image.value, // 我用的是二进制图片 }); //第3个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page3Image.value, // 我用的是二进制图片 }); //第4个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page4Image.value, // 我用的是二进制图片 }); //第5个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page5Image.value, // 我用的是二进制图片 }); //第6个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page6Image.value, // 我用的是二进制图片 }); //第7个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page7Image.value, // 我用的是二进制图片 }); //第8个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page8Image.value, // 我用的是二进制图片 }); //第9个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page9Image.value, // 我用的是二进制图片 }); //第10个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page10Image.value, // 我用的是二进制图片 }); // 11-20 //第11个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page11Image.value, // 我用的是二进制图片 }); //第12个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page12Image.value, // 我用的是二进制图片 }); //第13个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page13Image.value, // 我用的是二进制图片 }); //第14个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page14Image.value, // 我用的是二进制图片 }); //第15个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page15Image.value, // 我用的是二进制图片 }); //第16个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page16Image.value, // 我用的是二进制图片 }); //第17个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page17Image.value, // 我用的是二进制图片 }); //第18个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page18Image.value, // 我用的是二进制图片 }); //第19个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page19Image.value, // 我用的是二进制图片 }); //第20个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page20Image.value, // 我用的是二进制图片 }); //第21个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page21Image.value, // 我用的是二进制图片 }); //第22个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page22Image.value, // 我用的是二进制图片 }); //第23个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page23Image.value, // 我用的是二进制图片 }); //第24个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page24Image.value, // 我用的是二进制图片 }); //第25个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page25Image.value, // 我用的是二进制图片 }); //第26个幻灯片 ppt.addSlide().addImage({ ...optionsImage, data: page26Image.value, // 我用的是二进制图片 }); // 4. 生成PPT, 括号中的fileName,就是生成的 PPT名字,可以使用 .then 或者 .catch处理对应事件。 ppt.writeFile({ fileName: "分析报告.pptx" }); }; async function getAllPPtData() { const selectData = JSON.parse(localStorage.getItem("selectTopData")); let date = ""; date = selectData.date.split("-")[0] + selectData.date.split("-")[1] + selectData.date.split("-")[2]; let params = { scenesType: "XX社区", profileName: selectData.business === "全部" ? "" : selectData.business, flag: selectData.flag, codeId: selectData.areaCode, statDate: date, }; let res = await request(serviceModule.AllPptData, params); if (res.data.code === 200) { dataAll.dataAll = res.data.data; emit('handleDataAll',dataAll.dataAll) } else { ElMessage.error(res.data.msg); } // request(serviceModule.AllPptData, params).then((res) => { // if (res.data.code === 200) { // console.log("获取dead", res); // dataAll.dataAll = res.data.data; // } else { // ElMessage.error(res.data.msg); // } // }); } // onMounted(() => { // setTimeout(() => { // getAllPPtData(); // }, 1000); // }); defineExpose({ ppt, exportPPt, getAllPPtData, }); </script> <style lang="less"> .ppt-all { position: fixed; top: 0; left: 0; z-index: -9999; font-family: Source Han Sans CN; background-color: #ffffff; } .cm-width { width: 1920px; height: 1080px; // border: 1px solid red; font-family: Source Han Sans CN; box-sizing: border-box; background-image: url("@/assets/images/ppt/bg.png"); background-repeat: no-repeat; background-size: contain; position: relative; } .cm-pageNumber{ position: absolute; right: 30px; bottom: 30px; font-size: 26px; } .cm-active { color: rgba(22, 110, 244, 1) !important; font-size: 42px !important; font-weight: bold !important; } .ppt-all { .resultInfo { padding: 0 75px; text-align: left !important; } .desc { padding-left: 75px; padding-right: 75px; } }</style>