下载文件流
// 通过后端接口拿到文件流 export function getExport(url, parameter, method) { return request({ url: url, method: method || 'post', data: method !== 'get' ? parameter : null, params: method === 'get' ? parameter : null, responseType: 'blob' // 这一行是关键,拿到blob数据类型的文件 }) } 转载链接:https://www.cnblogs.com/buluzombie/p/16735403.html
下载xls文件:
downloadFile.js
export let downloadFile = function (res, filename) { // 将blob对象转为一个URL let blobURL = window.URL.createObjectURL(res) // 创建一个a标签 let tempLink = document.createElement('a') // 隐藏a标签 tempLink.style.display = 'none' // 设置a标签的href属性为blob对象转化的URL tempLink.href = blobURL // 给a标签添加下载属性 decodeURI 解码 tempLink.setAttribute('download', decodeURI(filename)) if (typeof tempLink.download === 'undefined') { tempLink.setAttribute('target', '_blank') } // 将a标签添加到body当中 document.body.appendChild(tempLink) // 启动下载 tempLink.click() // 下载完毕删除a标签 document.body.removeChild(tempLink) window.URL.revokeObjectURL(blobURL) }
import { downloadFile } from "@/utils/downloadFile"; <el-button @click="exportFile">下载文件</el-button> methords:{ exportFile(){ getExport(参数).then((res) => { downloadFile(res,'名称'); }); } }
下载word文档:
downloadFile.js
export function downloadWord(data, fileName, fileSuffix) { let fileTypeMime = '' // 文件 mime 类型,移动端必传,否则下载不成功;pc端可传可不传 switch (fileSuffix) { // 获取后缀对应的 mime case 'png': fileTypeMime = 'image/png'; break; case 'doc': fileTypeMime = 'application/msword'; break; case 'docx': fileTypeMime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; break; case 'jpg': case 'jpeg': fileTypeMime = 'image/jpeg'; break; case 'gif': fileTypeMime = 'image/gif'; break; case 'svg': fileTypeMime = 'image/svg+xml'; break; case 'tif': case 'tiff': fileTypeMime = 'image/tiff'; break; case 'txt': fileTypeMime = 'text/plain'; break; case 'ppt': fileTypeMime = 'application/vnd.ms-powerpoint'; break; case 'pptx': fileTypeMime = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; break; case 'xls': fileTypeMime = 'application/vnd.ms-excel'; break; case 'xlsx': fileTypeMime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; break; case 'zip': fileTypeMime = 'application/zip'; break; case '7z': fileTypeMime = 'application/x-7z-compressed'; break; } let blob = window.URL.createObjectURL(new Blob([data], { 'type': fileTypeMime })) let link = document.createElement('a') link.style.display = 'none' link.href = blob link.setAttribute('download', fileName + fileSuffix) document.body.appendChild(link) link.click() document.body.removeChild(link) //下载完成移除元素 window.URL.revokeObjectURL(blob) //释放掉 blob 对象 }
import { downloadFile } from "@/utils/downloadFile"; <el-button @click="exportFile">下载文件</el-button> methords:{ exportFile(){
getExport(参数).then((res) => { downloadWord(res, "名称", ".docx"); });
} }
下载pdf文件:
npm install html2canvas -S;
npm install jspdf -S;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | <strong>htmlPdf.js<br></strong> import html2Canvas from 'html2canvas' import JsPDF from 'jspdf' export default { install(Vue, options) { // 不分页 // Vue.prototype.getPdf = function () { // let title = this.exportPDFtitle; // html2Canvas(document.querySelector('#pdfDom'), { // // allowTaint: true, // useCORS: true, // // scale: 2, // 提升画面质量,但是会增加文件大小 // }).then((canvas) => { // const contentWidth = canvas.width // const contentHeight = canvas.height // /* 导出不分页处理 */ // const pageData = canvas.toDataURL('image/jpeg', 1.0) // const pdfWidth = (contentWidth + 10) / 2 * 0.75 // const pdfHeight = (contentHeight + 200) / 2 * 0.75 // 500为底部留白 // const imgWidth = pdfWidth // const imgHeight = (contentHeight / 2 * 0.75) // 内容图片这里不需要留白的距离 // const PDF = new JsPDF('', 'pt', [pdfWidth, pdfHeight, ]) // PDF.addImage(pageData, 'jpeg', 0, 0, imgWidth, imgHeight) // PDF.save(title + '.pdf') // }) // } // 分页处理 Vue.prototype.isSplit = function (nodes, index, pageHeight) { // 计算当前这块dom是否跨越了a4大小,以此分割 if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) { return true ; } return false ; }, Vue.prototype.uploadPdf = function () { let ST = document.documentElement.scrollTop || document.body.scrollTop; let SL = document.documentElement.scrollLeft || document.body.scrollLeft; document.documentElement.scrollTop = 0; document.documentElement.scrollLeft = 0; document.body.scrollTop = 0; document.body.scrollLeft = 0; //获取滚动条的位置并赋值为0,因为是el-dialog弹框,并且内容较多出现了纵向的滚动条,截图出来的效果只能截取到视图窗口显示的部分,超出窗口部分则无法生成。所以先将滚动条置顶 const A4_WIDTH = 592.28; const A4_HEIGHT = 841.89; let imageWrapper = document.querySelector( '#pdfDom' ) // 获取DOM let pageHeight = imageWrapper.scrollWidth / A4_WIDTH * A4_HEIGHT; let lableListID = imageWrapper.querySelectorAll( "p" ); // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割 for ( let i = 0; i < lableListID.length; i++) { let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight); if ( this .isSplit(lableListID, i, multiple * pageHeight)) { let divParent = lableListID[i].parentNode; // 获取该div的父节点 let newNode = document.createElement( 'div' ); newNode.className = 'emptyDiv' ; newNode.style.background = '#ffffff' ; let _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight); //留白 newNode.style.height = _H + 30 + 'px' ; newNode.style.width = '100%' ; let next = lableListID[i].nextSibling; // 获取div的下一个兄弟节点 // 判断兄弟节点是否存在 if (next) { // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后 divParent.insertBefore(newNode, next); } else { // 不存在则直接添加到最后,appendChild默认添加到divParent的最后 divParent.appendChild(newNode); } } } //接下来开始截图 this .$nextTick(() => { // nexttick可以保证要截图的部分全部执行完毕,具体用法自行百度... let title = this .exportPDFtitle; html2Canvas(imageWrapper, { allowTaint: true , // x: imageWrapper.getBoundingClientRect().left + 13, // 绘制的dom元素相对于视口的位置 // y: imageWrapper.getBoundingClientRect().top, width: imageWrapper.offsetWidth - 15, // 因为多出的需要剪裁掉, height: imageWrapper.offsetHeight, backgroundColor: "#FFF" , //一定要设置北京颜色,否则有的浏览器就会变花~,比如Edge useCORS: true , scale: 3, // 图片模糊 dpi: 350, //z }).then((canvas) => { let pdf = new JsPDF( 'p' , 'mm' , 'a4' ); //A4纸,纵向 let ctx = canvas.getContext( '2d' ), a4w = 190, a4h = 270, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277 // imgHeight = Math.floor(a4h * canvas.width / a4w), //按A4显示比例换算一页图像的像素高度 imgHeight = a4h * canvas.width / a4w, //按A4显示比例换算一页图像的像素高度 renderedHeight = 0; while (renderedHeight < canvas.height) { let 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' , 0.2), 'JPEG' , 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); //添加图像到页面,保留10mm边距 renderedHeight += imgHeight; if (renderedHeight < canvas.height) pdf.addPage(); //如果后面还有内容,添加一个空页 } // pdf.save('测试.pdf'); pdf.save(title + ".pdf" ) }) }) } } } |
main.js
// 生成PDF import htmlPdf from '@/utils/htmlPdf'; Vue.use(htmlPdf);
index.vue <!-- 生成PDF文件信息 --> <div ref="targetDom" id="pdfDom" class="pdfDom" v-show="pdfDomShow" style="width:90%; padding-left: 40px; padding-right: 40px; position: absolute; right: 3000px;" > <h1>基本信息</h1> <table border="1" cellspacing="0" cellpadding="0" class="table_class"> <tr> <td>信息1</td> <td>aaa</td> <td>信息2</td> <td>bbb</td> <td>信息3</td> <td>ccc</td> </tr> </table> </div>
<el-button @click="exportFile">下载文件</el-button>
methords:{
exportFile(){
this.$nextTick(() => {
this.uploadPdf();
});
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通