html2canvas 目标元素过长canvas渲染不全【折中方案】

Problem 使用html2canvas.js处理浏览器截屏时,发现当元素宽度超过某个阈值后会出现超出部分渲染异常现象。
Debug

html2canvas截屏,实质是dom转canvns,canvas转图片。
目标宽度20000+px
  • 无操作,copyDom显示正常,canvas宽高正常,但右侧元素显示为黑块,且位置居左。
  • html2canvas 目标元素过长canvas渲染不全【折中方案】
    文章图片
  • option添加foreignObjectRendering: true,copyDom显示正常,canvas宽高正常,但右侧原异常元素缺失部分文本。
  • html2canvas 目标元素过长canvas渲染不全【折中方案】
    文章图片
  • option指定width为10000,copyDom显示正常,canvas宽度10000,导出10000宽-图正常。
初步推断canvas渲染有宽度上限,百度一番仍无定论
Solution 首先不是视图外元素缺失的问题,试了很多都无结果。最后敲定折中方案就是根据宽度计算 拆分出图。
Old code
/** * @description html转图片导出 * @param ele * @param option * @param fileName * @param uuidKey */ export const handleHtml2Down = (ele, option, fileName, uuidKey) => { window.pageYOffset = 0; document.documentElement.scrollTop = 0 document.body.scrollTop = 0 const targetDom = document.querySelector(ele) const copyDom = targetDom.cloneNode(true) copyDom.style.width = targetDom.scrollWidth + 'px' copyDom.style.height = targetDom.scrollHeight + 'px' copyDom.style.position = 'absolute' copyDom.style.top = '0px' copyDom.style.zIndex = '-1' copyDom.style.backgroundColor = 'white' document.body.appendChild(copyDom) html2canvas(copyDom, { height: copyDom.scrollHeight, width: copyDom.scrollWidth, allowTaint: false, useCORS: true, ...option }).then((canvas => { copyDom.parentNode.removeChild(copyDom) canvas.style.width = parseFloat(canvas.style.width) * 0.8 + 'px' canvas.style.height = parseFloat(canvas.style.height) * 0.6 + 'px' let imgURL = canvas.toDataURL('image/png',1.0) const alink = document.createElement("a") alink.href = https://www.it610.com/article/imgURL let theName =fileName || getUUID(uuidKey) alink.download = `${theName}.png` alink.click() })) }

New code
/** * @description html转图片导出【宽度分页】 * @param ele 目标dom元素 * @param option html2canvas函数执行参数 * @param fileName 导出图片文件(可不传) * @param uuidKey uuid前缀字符(可不传) */ export const handleHtml2Down = async (ele, option, fileName, uuidKey) => { //reset this page scroll window.pageYOffset = 0; document.documentElement.scrollTop = 0 document.body.scrollTop = 0 //targetDom - target 2 img const targetDom = document.querySelector(ele) //copyDom - copy dom from targetDom const copyDom = targetDom.cloneNode(true) //copyWrapper - wrapper contain the copyDom , use for with-overflow const copyWrapper = document.createElement('div') //init the copyDom copyDom.style.width = targetDom.scrollWidth + 'px' copyDom.style.height = targetDom.scrollHeight + 'px' copyDom.style.transform = '' copyDom.style.margin = '0 0' //define the maxWidth:15000(px) const maxW = 15000 //define the val let urls = [], w = targetDom.scrollWidth,index=0 //init the copyWrapper copyWrapper.style.backgroundColor = 'white' copyWrapper.style.width = (w > maxW ? maxW : w) + 'px' copyWrapper.style.height = targetDom.scrollHeight + 'px' //fix the element copyWrapper.style.position = 'fixed' copyWrapper.style.top = '0px' //make sure the copyWrapper is invisible copyWrapper.style.zIndex = '-1' //use for pageControl copyWrapper.style.overflow = 'hidden' //execute dom append copyWrapper.appendChild(copyDom) document.body.appendChild(copyWrapper) //generate canvas from dom in Loop while (w > 0){ await html2canvas(copyWrapper, { height: copyWrapper.scrollHeight, width: (w > maxW ? maxW : w), foreignObjectRendering: true, allowTaint: false, useCORS: true, ...option }).then((canvas => { canvas.style.width = parseFloat(canvas.style.width) * 0.8 + 'px' canvas.style.height = parseFloat(canvas.style.height) * 0.6 + 'px' urls.push(canvas.toDataURL('image/png',1.0)) w = w - maxW index++ copyWrapper.style.width = w copyDom.style.marginLeft = `-${maxW * index}px` })) } //execute dom remove copyDom.parentNode.removeChild(copyDom) console.log(urls) //export urls & execute img download urls.forEach(url=>{ let alink = document.createElement("a") alink.href = https://www.it610.com/article/url alink.download = `${fileName || getUUID(uuidKey)}.png` alink.click() }) } expory getUUID = (preffix)=> { return preffix + 'i-am-uuid-123'}

Result html2canvas 目标元素过长canvas渲染不全【折中方案】
文章图片

html2canvas 目标元素过长canvas渲染不全【折中方案】
文章图片

End 【html2canvas 目标元素过长canvas渲染不全【折中方案】】thanks 4 read & welcome 4 leaving a message.

    推荐阅读