制作网站注册页面,网站任务界面,宿州城市建设投资网站,温州专业网站托管vue3.0生成压缩包#xff08;含在线地址、前端截图、前端文档#xff09; 需求描述效果开始下载插件包基本代码构造 点击下载按钮1.截图content元素#xff0c;并转化为pdfcanvas putImageData、getImageDatagetImageData 获取指定矩形区域的像素信息putImageData 将这些数据… vue3.0生成压缩包含在线地址、前端截图、前端文档 需求描述效果开始下载插件包基本代码构造 点击下载按钮1.截图content元素并转化为pdfcanvas putImageData、getImageDatagetImageData 获取指定矩形区域的像素信息putImageData 将这些数据放回画布从而实现对画布像素的编辑 2.提取富文本视频正则 str.match(regex) regex.execstr知识补充 3.base64和在线地址转blob4.下载成压缩包代码 全部代码 需求描述
内容区为富文本html渲染的内容要求点击下载后 需要有以下文件1.当前内容的页面即渲染内容截图且需要将截图转化成pdf2.提取html内容区的视频单独下载3.后端返回的附件地址下载附件文档4.再将以上文件总结成压缩包
效果 开始
下载插件包
html2canvas 截图
npm install html2canvas --save
//或
yarn add html2canvasjspd 生成pdf插件
npm install jspdf --save
//或
yarn add jspdfjszip压缩文件
npm install jszip --save
//或
yarn add jszip保存文件的JavaScript库
npm install file-saver --save
//或
yarn add file-saver一起安装
npm i file-saver jszip html2canvas jspdf --save基本代码构造 div v-htmlcontentValue /div //用于展示div refcontent v-htmlcontentValue idcontent/div //用于截图并转化成pdf 我们调整使他不在可视范围内(不需要视频 同时把视频隐藏)-----// js
import html2canvas from html2canvas;
import { jsPDF } from jspdf;
import JSZip from jszip;
import FileSaver from file-saver;
-----const content refany(null); //ref实例const contentValue refstring(); //contentValue富文本html数据const downloadFileUrl refstring[]([]); //压缩包下载数组const pdfValuerefstring()// 获取详情const getDetail async (id: string) {const res await 你的详情api({id,});if (res) {contentValue.value res;// 添加视频链接downloadFileUrl.value getVideo(res.content);if (res?.annexList?.length) {// 添加附件链接downloadFileUrl.value.push(res.annexList[0].url);}}};----- //less#content {position: absolute;left: 100000px;top: 0;/deep/video {display: none;}
}点击下载按钮
1.截图content元素并转化为pdf const exportToPDF () {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 new jsPDF(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);page.width canvas.width;page.height Math.min(imgHeight, canvas.height - renderedHeight); // 可能内容不足一页// 用getImageData剪裁指定区域并画到前面创建的canvas对象中page.getContext(2d).putImageData(ctx.getImageData(0,renderedHeight,canvas.width,Math.min(imgHeight, canvas.height - renderedHeight)),0,0);pdf.addImage(page.toDataURL(image/jpeg, 1.0),JPEG,20,20,a4w,Math.min(a4h, (a4w * page.height) / page.width)); // 添加图像到页面保留10mm边距renderedHeight imgHeight;if (renderedHeight canvas.height) {pdf.addPage(); // 如果后面还有内容添加一个空页}}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.提取富文本视频 //单独提取富文本视频链接const getVideo (str: string) {const regex /video.*?src[]([^])[]/g;const videoTags str.match(regex);// console.log(videoTags) arr[0]代表第一个匹配项arr[1]代表第二个匹配项...数组length代表有几个匹配项// [video poster controlstrue widthauto heightautosource 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) {videoUrls.push(match[1]); // match[1] 匹配到的视频地址}}}return videoUrls;};//ps 单独提取文字正则 str.replace(/[^]/g, )正则 str.match(regex) regex.execstr知识补充 3.base64和在线地址转blob
const dataURLtoFile (dataurl: string, type: string) {return new Promise((resolve, reject) {if (type http) {//通过请求获取文件blob格式let xmlhttp new XMLHttpRequest();xmlhttp.open(GET, url, true);xmlhttp.responseType blob;xmlhttp.onload function () {if (xmlhttp.status 200) {resolve(xmlhttp.response);} else {reject(xmlhttp.response);}};xmlhttp.send();} else {let arr dataurl.split(,);let bstr atob(arr[1]);let n bstr.length;let u8arr new Uint8Array(n);while (n--) {u8arr[n] bstr.charCodeAt(n);}resolve(u8arr);}});};4.下载成压缩包代码 // 下载全部附件const downloadFile async () {var blogTitle 附件批量下载; // 下载后压缩包的名称var zip new JSZip();var promises [];for (let item of downloadFileUrl.value) {if (item) {// 在线地址转blob 添加至进程const promise dataURLtoFile(item, http).then((data) {// 下载文件, 并存成ArrayBuffer对象(blob)let fileName getFileName(item); //文件名 这里可以自己命名 不用调这个方法 博主需求是截取地址后面的zip.file(fileName, data, { binary: true });});promises.push(promise);} else {// answer地址不存在时提示alert(附件地址错误下载失败);}}// 单独加富文本pdf blobif (pdfUrl.value) {const contentPromise dataURLtoFile(pdfUrl.value, base64).then((data) {zip.file(content.pdf, data, { binary: true });});promises.push(contentPromise);}Promise.all(promises).then(() {zip.generateAsync({type: blob,}).then((content) {// 生成二进制流FileSaver.saveAs(content, blogTitle); // 利用file-saver保存文件 blogTitle:自定义文件名});}).catch((res) {alert(文件压缩失败);});};// 获取文件名const getFileName (filePath: string) {var startIndex filePath.lastIndexOf(/);if (startIndex ! -1)return filePath.substring(startIndex 1, filePath.length).toLowerCase();else return ;};
全部代码
templatedivdivdivpclickdownloadAllFile()a-icon typeicon-xiazai/w-icon 下载/p/div/divdivclasstext-contentv-htmldetaileInfo.content/divdivclasstext-contentrefcontentidcontentdiv v-htmldetaileInfo.content/div/div/div
/templatescript langts
import { defineComponent, onMounted, ref } from vue;
import html2canvas from html2canvas;
import { jsPDF } from jspdf;
import JSZip from jszip;
import FileSaver from file-saver;export default defineComponent({name: announcementDetail,setup() {const detaileInfo refany({});const content refany(null);const downloadFileUrl refstring[]([]);const pdfUrl refstring();// 获取详情const getDetail async () {const res await 你的api({id: 你的id,});if (res) {detaileInfo.value res;// 添加视频链接downloadFileUrl.value getVideo(res.content);if (res?.annexList?.length) {// 添加附件链接downloadFileUrl.value.push(res.annexList[0].url);}}};//单独提取富文本视频链接const getVideo (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) {videoUrls.push(match[1]); // match[1] 匹配到的视频地址}}}return videoUrls;};const downloadAllFile () {exportToPDF();};const exportToPDF () {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 new jsPDF(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);page.width canvas.width;page.height Math.min(imgHeight, canvas.height - renderedHeight); // 可能内容不足一页// 用getImageData剪裁指定区域并画到前面创建的canvas对象中page.getContext(2d).putImageData(ctx.getImageData(0,renderedHeight,canvas.width,Math.min(imgHeight, canvas.height - renderedHeight)),0,0);pdf.addImage(page.toDataURL(image/jpeg, 1.0),JPEG,20,20,a4w,Math.min(a4h, (a4w * page.height) / page.width)); // 添加图像到页面保留10mm边距renderedHeight imgHeight;if (renderedHeight canvas.height) {pdf.addPage(); // 如果后面还有内容添加一个空页}}pdfUrl.value pdf.output(datauristring); // 获取base64PdfdownloadFile();});};//返回blob值 在线地址和前端生成的base64编码const dataURLtoFile (dataurl: string, type: string) {return new Promise((resolve, reject) {if (type http) {//通过请求获取文件blob格式let xmlhttp new XMLHttpRequest();xmlhttp.open(GET, url, true);xmlhttp.responseType blob;xmlhttp.onload function () {if (xmlhttp.status 200) {resolve(xmlhttp.response);} else {reject(xmlhttp.response);}};xmlhttp.send();} else {let arr dataurl.split(,);let bstr atob(arr[1]);let n bstr.length;let u8arr new Uint8Array(n);while (n--) {u8arr[n] bstr.charCodeAt(n);}resolve(u8arr);}});};// 下载全部附件const downloadFile async () {var blogTitle 附件批量下载; // 下载后压缩包的名称var zip new JSZip();var promises [];for (let item of downloadFileUrl.value) {if (item) {// 在线地址转blob 添加至进程const promise dataURLtoFile(item, http).then((data) {// 下载文件, 并存成ArrayBuffer对象(blob)let fileName getFileName(item); //文件名zip.file(fileName, data, { binary: true });});promises.push(promise);} else {alert(附件地址错误下载失败);}}// 单独加富文本blobif (pdfUrl.value) {const contentPromise dataURLtoFile(pdfUrl.value, base64).then((data) {zip.file(content.pdf, data, { binary: true });});promises.push(contentPromise);}Promise.all(promises).then(() {zip.generateAsync({type: blob,}).then((content) {// 生成二进制流FileSaver.saveAs(content, blogTitle); // 利用file-saver保存文件 blogTitle:自定义文件名});}).catch((res) {alert(文件压缩失败);});};// 获取文件名const getFileName (filePath: string) {var startIndex filePath.lastIndexOf(/);if (startIndex ! -1)return filePath.substring(startIndex 1, filePath.length).toLowerCase();else return ;};onMounted(() {getDetail();});return {content,detaileInfo,downloadAllFile,};},
});
/scriptstyle langless scoped
.text-content {font-family: PingFang SC;font-weight: 400;font-size: 15px;letter-spacing: 0.06px;line-height: 30px;text-align: left;color: #666;width: 100%;/deep/video,/deep/img {width: 100%;}
}
#content {position: absolute;left: 100000px;top: 0;.label {display: inline-block;}/deep/video {display: none;}
}
/style