当前位置: 首页 > news >正文

html-docx-js和file-saver实现html导出word

依赖html-docx-js,file-saver,html2canvas

import { asBlob } from 'html-docx-js/dist/html-docx';
import { saveAs } from 'file-saver';
import html2Canvas from 'html2canvas';const handleImageToBase64 = (cloneEle) => {let imgElements = cloneEle.getElementsByTagName('img');let canvas = document.createElement('canvas');let ctx = canvas.getContext('2d');const promises = Array.from(imgElements).map((item) => {return new Promise((resolve) => {item.onload = () => {ctx.clearRect(0, 0, item.width, item.height);canvas.width = item.width;canvas.height = item.height;ctx.drawImage(item, 0, 0, item.width, item.height);let ext = '';if (item.src.indexOf('data:image/svg+xml;base64') === 0) {ext = 'png';} else {ext = item.src.substring(item.src.lastIndexOf('.') + 1).toLowerCase();}let dataURL = canvas.toDataURL('image/' + ext);item.setAttribute('src', dataURL);resolve();};});});canvas.remove();return promises;
};const handleCanvasToImage = (cloneEle) => {const canvasElements = cloneEle.getElementsByTagName('canvas');const promises = Array.from(canvasElements).map((ca, index) => {return new Promise((resolve) => {const url = ca.toDataURL('image/png', 1);const img = new Image();img.onload = () => {URL.revokeObjectURL(url);resolve();};img.src = url;// 生成img插入clone的dom的canvas之前canvasElements[index].parentNode.insertBefore(img, canvasElements[index]);});});// 移除原来的canvasArray.from(canvasElements).forEach((ca) => ca.parentNode.removeChild(ca));return promises;
};const handleSvgToImage = (cloneEle) => {const svgElements = cloneEle.getElementsByTagName('svg');Array.from(svgElements).forEach((svg) => {// 将SVG元素转换为PNG图片const img = new Image();img.src = 'data:image/svg+xml;base64,' + window.btoa(encodeURIComponent(svg.outerHTML).replace(/%([0-9A-F]{2})/g, function(match, p1) {return String.fromCharCode('0x' + p1);}));// 将图片插入到SVG元素的位置svg.parentNode.insertBefore(img, svg);// 移除原来的SVG元素svg.parentNode.removeChild(svg);});
};const handleCodeToImage = (ele, cloneEle) => {let codeElements = ele.querySelectorAll('pre code');let cloneCodeElements = cloneEle.querySelectorAll('pre code');const promises = Array.from(codeElements).map((item, index) => {return new Promise((resolve) => {const pre = item.parentNode;html2Canvas(pre, {imageTimeout: 2000,logging: false,scrollY: 0,scrollX: 0,scale: window.devicePixelRatio * 1.2, // 添加的scale 参数width: item.offsetWidth + 32,allowTaint: false,useCORS: true, // 开启跨域}).then(canvas => {// 将 Canvas 转换为图片let dataURL = canvas.toDataURL('image/png');// 创建一个新的 <img> 元素并设置其 src 属性const img = new Image();img.src = dataURL;// 将图片插入到SVG元素的位置const clonePre = cloneCodeElements[index].parentNode;clonePre.parentNode.insertBefore(img, clonePre);// 移除原来的SVG元素clonePre.parentNode.removeChild(clonePre);resolve();});});});return promises;
};// 表格虚线 向右偏移10px左右
const handleTableStyle = (cloneEle) => {let tableElements = cloneEle.getElementsByTagName('table');Array.from(tableElements).forEach((table) => {table.style.borderCollapse = table.style.borderCollapse || 'collapse';table.border = table.border || '1';table.style.marginLeft = '10px';});let thElements = cloneEle.getElementsByTagName('th');Array.from(thElements).forEach((th) => {th.style.backgroundColor = '#f0f0f0';});
};const getMarkdownCss = () => {return `body {color: #383c4a;font-family: -apple-system, blinkmacsystemfont, "Segoe UI", helvetica, arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";font-size: 12px;word-wrap: break-word;}`;
};const handleHtml = async (ele, cloneEle, type) => {const canvasPromises = handleCanvasToImage(cloneEle);await Promise.all(canvasPromises);handleSvgToImage(cloneEle);const imagePromises = handleImageToBase64(cloneEle);const codePromises = handleCodeToImage(ele, cloneEle);await Promise.all(codePromises);await Promise.all(imagePromises);handleTableStyle(cloneEle);let cssString = '';if (type === 'markdown') {cssString = getMarkdownCss();}const innerHtml = cloneEle.outerHTML// strong在word中不生效问题.replace(/<strong class="(.*?)">(.*?)<\/strong>/g, '<b class="$1">$2</b>').replace(/<mark/g, '<span').replace(/<\/mark>/g, '</span>');const htmlString = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head><style type="text/css">${cssString}</style> </head><body>${innerHtml}</body></html>`;return htmlString;
};export default function exportWord({ selector, name = 'export', type = 'markdown' }) {if (!selector) return Promise.reject();// eslint-disable-next-line no-async-promise-executorreturn new Promise(async (resolve) => {const ele = document.querySelector(selector);const cloneEle = ele.cloneNode(true);const htmlString = await handleHtml(ele, cloneEle, type);const converted = asBlob(htmlString);saveAs(converted, `${name}.docx`);resolve();});}}

页面调用

exportWord({selector: '.report-container'});

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • vue3前端开发-小兔鲜项目-登录组件的开发表单验证
  • Android WebViewClient 的 `shouldOverrideUrlLoading` 方法
  • 学习在测试时学习(Learning at Test Time): 具有表达性隐藏状态的循环神经网络(RNNs)
  • Linux中tomcat下载教程
  • 国产系统银河麒麟SP10桌面版安装nvidia 4060TI驱动
  • 算法第十五天:leetcode19.删除链表的倒数第N个节点
  • Visual stdio code 运行C项目环境搭建
  • openCv -- 优势
  • Docker 搭建Elasticsearch详细步骤
  • 【C++】模板详解
  • 如何撤销/回滚远程修改
  • Springboot项目的行为验证码AJ-Captcha(源码解读)
  • cpp程序设计实践,类实现树链刨分以及计算几何类
  • ASP.NET中的六大对象有哪些?以及各自的功能以及使用方式
  • Android中systrace配置及注意问题
  • JavaScript-如何实现克隆(clone)函数
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • Android 架构优化~MVP 架构改造
  • Android框架之Volley
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • C学习-枚举(九)
  • ECMAScript6(0):ES6简明参考手册
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • java概述
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Median of Two Sorted Arrays
  • Python语法速览与机器学习开发环境搭建
  • quasar-framework cnodejs社区
  • spark本地环境的搭建到运行第一个spark程序
  • vue-router的history模式发布配置
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 技术发展面试
  • 看域名解析域名安全对SEO的影响
  • 力扣(LeetCode)22
  • 码农张的Bug人生 - 初来乍到
  • 新手搭建网站的主要流程
  • 延迟脚本的方式
  • Hibernate主键生成策略及选择
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • ​Linux·i2c驱动架构​
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #AngularJS#$sce.trustAsResourceUrl
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (11)MSP430F5529 定时器B
  • (52)只出现一次的数字III
  • (LeetCode 49)Anagrams
  • (Matlab)使用竞争神经网络实现数据聚类
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (三)elasticsearch 源码之启动流程分析
  • (转)Sublime Text3配置Lua运行环境
  • (转)winform之ListView
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版