依赖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' ) ; Array. from ( imgElements) . forEach ( ( item ) => { canvas. width = item. width; canvas. height = item. height; ctx. drawImage ( item, 0 , 0 , item. width, item. height) ; let ext = item. src. substring ( item. src. lastIndexOf ( '.' ) + 1 ) . toLowerCase ( ) ; let dataURL = canvas. toDataURL ( 'image/' + ext) ; item. setAttribute ( 'src' , dataURL) ; } ) ; canvas. remove ( ) ;
} ; 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; canvasElements[ index] . parentNode. insertBefore ( img, canvasElements[ index] ) ; } ) ; } ) ; Array. from ( canvasElements) . forEach ( ( ca ) => ca. parentNode. removeChild ( ca) ) ; return promises;
} ; const handleSvgToImage = ( cloneEle ) => { const svgElements = cloneEle. getElementsByTagName ( 'svg' ) ; Array. from ( svgElements) . forEach ( ( svg ) => { 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. parentNode. insertBefore ( img, 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 , width : ele. clientWidth / 1.5 , allowTaint : false , useCORS : true , } ) . then ( canvas => { let dataURL = canvas. toDataURL ( 'image/png' ) ; const img = new Image ( ) ; img. src = dataURL; const clonePre = cloneCodeElements[ index] . parentNode; clonePre. parentNode. insertBefore ( img, clonePre) ; clonePre. parentNode. removeChild ( clonePre) ; resolve ( ) ; } ) ; } ) ; } ) ; return promises;
} ;
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 getCss = ( ) => { 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 ) => { const canvasPromises = handleCanvasToImage ( cloneEle) ; handleSvgToImage ( cloneEle) ; const codePromises = handleCodeToImage ( ele, cloneEle) ; await Promise. all ( canvasPromises) ; await Promise. all ( codePromises) ; handleImageToBase64 ( cloneEle) ; handleTableStyle ( cloneEle) ; let cssString = '' ; cssString = getCss ( ) ; const innerHtml = cloneEle. outerHTML. 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' } ) { if ( ! selector) return Promise. reject ( ) ; return new Promise ( async ( resolve ) => { const ele = document. querySelector ( selector) ; const cloneEle = ele. cloneNode ( true ) ; const htmlString = await handleHtml ( ele, cloneEle) ; const converted = asBlob ( htmlString) ; saveAs ( converted, ` ${ name} .docx ` ) ; resolve ( ) ; } ) ; }
页面调用
exportWord ( { selector : '.report-container' } ) ;