0


vue3.0 根据富文本html页面生成压缩包(含视频在线地址、图片在线地址、前端截图、前端文档)

vue3.0生成压缩包(含在线地址、前端截图、前端文档)

需求描述

  • 内容区为富文本html渲染的内容
  • 要求点击下载后 需要有以下文件
  • 1.当前内容的页面,即渲染内容截图,且需要将截图转化成pdf
  • 2.提取html内容区的视频,单独下载
  • 3.后端返回的附件地址,下载附件文档
  • 4.再将以上文件总结成压缩包在这里插入图片描述

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

开始

下载插件包

  • html2canvas 截图
  1. npm install html2canvas --save
  2. //或
  3. yarn add html2canvas
  • jspd 生成pdf插件
  1. npm install jspdf --save
  2. //或
  3. yarn add jspdf
  • jszip压缩文件
  1. npm install jszip --save
  2. //或
  3. yarn add jszip
  • 保存文件的JavaScript库
  1. npm install file-saver --save
  2. //或
  3. yarn add file-saver
  • 一起安装
  1. npm i file-saver jszip html2canvas jspdf --save

基本代码构造

  1. <div v-html="contentValue"></div>//用于展示<div ref="content" v-html="contentValue" id="content"></div>//用于截图并转化成pdf 我们调整使他不在可视范围内(不需要视频 同时把视频隐藏)-----// jsimport html2canvas from"html2canvas";import{ jsPDF }from"jspdf";import JSZip from"jszip";import FileSaver from"file-saver";-----const content = ref<any>(null);//ref实例const contentValue= ref<string>("");//contentValue富文本html数据const downloadFileUrl = ref<string[]>([]);//压缩包下载数组const pdfValue=ref<string>("")// 获取详情constgetDetail=async(id: string)=>{const res =await你的详情api({
  2. id,});if(res){
  3. contentValue.value = res;// 添加视频链接
  4. downloadFileUrl.value =getVideo(res.content);if(res?.annexList?.length){// 添加附件链接
  5. downloadFileUrl.value.push(res.annexList[0].url);}}};-----//less
  6. #content {position: absolute;left: 100000px;top:0;/deep/video {display: none;}}

点击下载按钮

1.截图content元素,并转化为pdf

  1. constexportToPDF=()=>{const dom = content.value;html2canvas(dom,{useCORS:true,//解决网络图片跨域问题width: dom.width,height: dom.height,windowWidth: dom.scrollWidth,dpi: window.devicePixelRatio *4,// 将分辨率提高到特定的DPI 提高四倍scale:4,// 按比例增加分辨率backgroundColor:"#fff",// 背景}).then((canvas)=>{const pdf =newjsPDF("p","mm","a4");// A4纸,纵向const ctx = canvas.getContext("2d");const a4w =170;const a4h =250;// A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257const imgHeight = Math.floor((a4h * canvas.width)/ a4w);// 按A4显示比例换算一页图像的像素高度let renderedHeight =0;while(renderedHeight < canvas.height){const page = document.createElement("canvas");
  2. page.width = canvas.width;
  3. page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
  4. page
  5. .getContext("2d").putImageData(
  6. ctx.getImageData(0,
  7. renderedHeight,
  8. canvas.width,
  9. Math.min(imgHeight, canvas.height - renderedHeight)),0,0);
  10. pdf.addImage(
  11. page.toDataURL("image/jpeg",1.0),"JPEG",20,20,
  12. a4w,
  13. Math.min(a4h,(a4w * page.height)/ page.width));// 添加图像到页面,保留10mm边距
  14. renderedHeight += imgHeight;if(renderedHeight < canvas.height){
  15. pdf.addPage();// 如果后面还有内容,添加一个空页}}
  16. pdfValue.value = pdf.output("datauristring");// 获取base64Pdf});

canvas putImageData、getImageData

getImageData 获取指定矩形区域的像素信息

ctx.getImageData(x,y,width,height)

属性描述x开始复制的左上角位置的 x 坐标(以像素计)。y开始复制的左上角位置的 y 坐标(以像素计)。width要复制的矩形区域的宽度。height要复制的矩形区域的高度。

putImageData 将这些数据放回画布,从而实现对画布像素的编辑

ctx.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)

属性描述imgData规定要放回画布的 ImageData 对象 ;xImageData 对象左上角的 x 坐标,以像素计;yImageData 对象左上角的 y 坐标,以像素计;dirtyX可选。水平值(x),以像素计,在画布上放置图像的位置;dirtyY可选。水平值(y),以像素计,在画布上放置图像的位置;dirtyWidth可选。在画布上绘制图像所使用的宽度;dirtyHeight可选。在画布上绘制图像所使用的高度

  • ImageData 结构:每个ImageData对象包含三个属性: width:图像数据的宽度(以像素为单位)。 height:图像数据的高度(以像素为单位)。 data:一个一维数组,包含图像数据的RGBA值。每个像素由四个连续的数组元素表示,分别对应红、绿、蓝和透明度(alpha)通道。每个通道的值都是一个0到255之间的整数。

2.提取富文本视频

  1. //单独提取富文本视频链接constgetVideo=(str: string)=>{const regex =/<video.*?src=["']([^"']+)["']/g;const videoTags = str.match(regex);// console.log(videoTags) arr[0]代表第一个匹配项,arr[1]代表第二个匹配项...,数组length代表有几个匹配项// ["<video poster="" controls="true" width="auto" height="auto"><source src="你的地址""]const videoUrls =[];if(videoTags){for(let i =0; i < videoTags.length; i++){const match = regex.exec(videoTags[i]);// console.log(match) [0]代表匹配项,[≥1]代表捕获的group。index是匹配的第一个字符索引,input代表str字符串// 0: "<video poster=\"\" controls=\"true\" width=\"auto\" height=\"auto\"><source src=\"你的地址\""// 1: "你的地址"// index: 0//input: "<video poster=\"\" controls=\"true\" width=\"auto\" height=\"auto\"><source src=\"你的地址\""if(match){
  2. videoUrls.push(match[1]);// match[1] 匹配到的视频地址}}}return videoUrls;};//ps 单独提取文字正则 str.replace(/<[^>]+>/g, "")

正则 str.match(regex) regex.exec(str)知识补充

在这里插入图片描述

3.base64和在线地址转blob

  1. constdataURLtoFile=(dataurl: string,type: string)=>{returnnewPromise((resolve, reject)=>{if(type ==="http"){//通过请求获取文件blob格式let xmlhttp =newXMLHttpRequest();
  2. xmlhttp.open("GET", url,true);
  3. xmlhttp.responseType ="blob";
  4. xmlhttp.onload=function(){if(xmlhttp.status ==200){resolve(xmlhttp.response);}else{reject(xmlhttp.response);}};
  5. xmlhttp.send();}else{let arr = dataurl.split(",");let bstr =atob(arr[1]);let n = bstr.length;let u8arr =newUint8Array(n);while(n--){
  6. u8arr[n]= bstr.charCodeAt(n);}resolve(u8arr);}});};

4.下载成压缩包代码

  1. // 下载全部附件constdownloadFile=async()=>{var blogTitle =`附件批量下载`;// 下载后压缩包的名称var zip =newJSZip();var promises =[];for(let item of downloadFileUrl.value){if(item){// 在线地址转blob 添加至进程const promise =dataURLtoFile(item,"http").then((data)=>{// 下载文件, 并存成ArrayBuffer对象(blob)let fileName =getFileName(item);//文件名 这里可以自己命名 不用调这个方法 博主需求是截取地址后面的
  2. zip.file(fileName, data,{binary:true});});
  3. promises.push(promise);}else{// answer地址不存在时提示alert(`附件地址错误,下载失败`);}}// 单独加富文本pdf blobif(pdfUrl.value){const contentPromise =dataURLtoFile(pdfUrl.value,"base64").then((data)=>{
  4. zip.file("content.pdf", data,{binary:true});});
  5. promises.push(contentPromise);}
  6. Promise.all(promises).then(()=>{
  7. zip
  8. .generateAsync({type:"blob",}).then((content)=>{// 生成二进制流
  9. FileSaver.saveAs(content, blogTitle);// 利用file-saver保存文件 blogTitle:自定义文件名});}).catch((res)=>{alert("文件压缩失败");});};// 获取文件名constgetFileName=(filePath: string)=>{var startIndex = filePath.lastIndexOf("/");if(startIndex !=-1)return filePath.substring(startIndex +1, filePath.length).toLowerCase();elsereturn"";};

全部代码

  1. <template><div><div><div><p
  2. @click="downloadAllFile()"><a-icon type="icon-xiazai"></w-icon> 下载
  3. </p></div></div><div
  4. class="text-content"
  5. v-html="detaileInfo.content"></div><div
  6. class="text-content"
  7. ref="content"
  8. id="content"><div v-html="detaileInfo.content"></div></div></div></template><script lang="ts">import{ defineComponent, onMounted, ref }from"vue";import html2canvas from"html2canvas";import{ jsPDF }from"jspdf";import JSZip from"jszip";import FileSaver from"file-saver";exportdefaultdefineComponent({name:"announcementDetail",setup(){const detaileInfo = ref<any>({});const content = ref<any>(null);const downloadFileUrl = ref<string[]>([]);const pdfUrl = ref<string>("");// 获取详情constgetDetail=async()=>{const res =await你的api({id:"你的id",});if(res){
  9. detaileInfo.value = res;// 添加视频链接
  10. downloadFileUrl.value =getVideo(res.content);if(res?.annexList?.length){// 添加附件链接
  11. downloadFileUrl.value.push(res.annexList[0].url);}}};//单独提取富文本视频链接constgetVideo=(str: string)=>{const regex =/<video.*?src=["']([^"']+)["']/g;const videoTags = str.match(regex);const videoUrls =[];if(videoTags){for(let i =0; i < videoTags.length; i++){const match = regex.exec(videoTags[i]);if(match){
  12. videoUrls.push(match[1]);// match[1] 匹配到的视频地址}}}return videoUrls;};constdownloadAllFile=()=>{exportToPDF();};constexportToPDF=()=>{const dom = content.value;html2canvas(dom,{useCORS:true,//解决网络图片跨域问题width: dom.width,height: dom.height,windowWidth: dom.scrollWidth,dpi: window.devicePixelRatio *4,// 将分辨率提高到特定的DPI 提高四倍scale:4,// 按比例增加分辨率backgroundColor:"#fff",// 背景}).then((canvas)=>{// eslint-disable-next-line new-capconst pdf =newjsPDF("p","mm","a4");// A4纸,纵向const ctx = canvas.getContext("2d");const a4w =170;const a4h =250;// A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257const imgHeight = Math.floor((a4h * canvas.width)/ a4w);// 按A4显示比例换算一页图像的像素高度let renderedHeight =0;while(renderedHeight < canvas.height){const page = document.createElement("canvas");
  13. page.width = canvas.width;
  14. page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
  15. page
  16. .getContext("2d").putImageData(
  17. ctx.getImageData(0,
  18. renderedHeight,
  19. canvas.width,
  20. Math.min(imgHeight, canvas.height - renderedHeight)),0,0);
  21. pdf.addImage(
  22. page.toDataURL("image/jpeg",1.0),"JPEG",20,20,
  23. a4w,
  24. Math.min(a4h,(a4w * page.height)/ page.width));// 添加图像到页面,保留10mm边距
  25. renderedHeight += imgHeight;if(renderedHeight < canvas.height){
  26. pdf.addPage();// 如果后面还有内容,添加一个空页}}
  27. pdfUrl.value = pdf.output("datauristring");// 获取base64PdfdownloadFile();});};//返回blob值 在线地址和前端生成的base64编码constdataURLtoFile=(dataurl: string,type: string)=>{returnnewPromise((resolve, reject)=>{if(type ==="http"){//通过请求获取文件blob格式let xmlhttp =newXMLHttpRequest();
  28. xmlhttp.open("GET", url,true);
  29. xmlhttp.responseType ="blob";
  30. xmlhttp.onload=function(){if(xmlhttp.status ==200){resolve(xmlhttp.response);}else{reject(xmlhttp.response);}};
  31. xmlhttp.send();}else{let arr = dataurl.split(",");let bstr =atob(arr[1]);let n = bstr.length;let u8arr =newUint8Array(n);while(n--){
  32. u8arr[n]= bstr.charCodeAt(n);}resolve(u8arr);}});};// 下载全部附件constdownloadFile=async()=>{var blogTitle =`附件批量下载`;// 下载后压缩包的名称var zip =newJSZip();var promises =[];for(let item of downloadFileUrl.value){if(item){// 在线地址转blob 添加至进程const promise =dataURLtoFile(item,"http").then((data)=>{// 下载文件, 并存成ArrayBuffer对象(blob)let fileName =getFileName(item);//文件名
  33. zip.file(fileName, data,{binary:true});});
  34. promises.push(promise);}else{alert(`附件地址错误,下载失败`);}}// 单独加富文本blobif(pdfUrl.value){const contentPromise =dataURLtoFile(pdfUrl.value,"base64").then((data)=>{
  35. zip.file("content.pdf", data,{binary:true});});
  36. promises.push(contentPromise);}
  37. Promise.all(promises).then(()=>{
  38. zip
  39. .generateAsync({type:"blob",}).then((content)=>{// 生成二进制流
  40. FileSaver.saveAs(content, blogTitle);// 利用file-saver保存文件 blogTitle:自定义文件名});}).catch((res)=>{alert("文件压缩失败");});};// 获取文件名constgetFileName=(filePath: string)=>{var startIndex = filePath.lastIndexOf("/");if(startIndex !=-1)return filePath.substring(startIndex +1, filePath.length).toLowerCase();elsereturn"";};onMounted(()=>{getDetail();});return{
  41. content,
  42. detaileInfo,
  43. downloadAllFile,};},});</script><style lang="less" scoped>.text-content {
  44. font-family:"PingFang SC";
  45. font-weight:400;
  46. font-size: 15px;
  47. letter-spacing:0.06px;
  48. line-height: 30px;
  49. text-align: left;color: #666;width:100%;/deep/video,/deep/img {width:100%;}}
  50. #content {position: absolute;left: 100000px;top:0;.label {display: inline-block;}/deep/video {display: none;}}</style>
标签: 前端 html 音视频

本文转载自: https://blog.csdn.net/weixin_43787651/article/details/144129653
版权归原作者 跳跳的小古风 所有, 如有侵权,请联系我们删除。

“vue3.0 根据富文本html页面生成压缩包(含视频在线地址、图片在线地址、前端截图、前端文档)”的评论:

还没有评论