纯JS前端实现HTML页面导出PDF的完整流程与代码解析

作者:微光

时间:2026-10-21

浏览:180

本文介绍在纯前端环境下,利用html2canvas和jsPDF将HTML页面导出为PDF的完整方案。重点解决SVG图片渲染、Glyphicons字体图标转换及页面样式保留问题,通过Canvas中转生成高清PDF,提供可直接运行的JavaScript代码示例。

文章目录

HTML转PDF需求背景与方案筛选

在Web项目开发过程中,常遇到需要将整个网页页面导出为PDF格式的需求,且必须完整保留页面上的表格、SVG矢量图以及所有CSS样式。

核心诉求类似于执行一次全屏截图,并将截取的页面内容保存为PDF文件。

此类需求往往较为复杂。

目前实现HTML转PDF的技术方案主要有以下几种:

第一种是利用浏览器自带的打印或导出功能。但这无法满足系统内部主动触发导出PDF的功能要求,因此该方案不可行。

第二种方案是使用第三方工具,例如wkhtmltopdf。经测试,该工具在项目中表现不佳,且对SVG图片的支持存在缺陷,故排除。

第三种方案是通过iText等后端库生成Java文件。由于目标页面为动态页面,直接传输至后端会导致大量CSS样式丢失,因此该方案也不适用。

鉴于上述方案均不理想,最终确定采用“HTML转图片,再由图片生成PDF”的折中策略。为满足用户导出下载且保留样式的需求,必须采用纯前端JavaScript实现。

HTML转Canvas环节,选用html2canvas库,该库应用广泛,此处不再赘述。

核心实现流程:SVG与字体图标处理

难点在于SVG图片的处理,html2canvas无法直接渲染SVG标签。经调研,选用canvg库(源自Google)将SVG内容转换为Canvas。此外,还需解决glyphicons等字体图标在不同浏览器下渲染不一致的问题,最终方案是通过字符编码(char code)替换字体图标,并在Canvas中重新绘制。生成图片后,利用jsPDF库生成最终PDF文件。经过大半天的调试,整个流程已打通,后续将分步展示代码。

第一步:遍历目标DOM节点,将所有SVG元素替换为Canvas元素。

SVG元素转Canvas实现


svg2canvas: function(targetElem) {
 var svgElem = targetElem.find('svg');
 svgElem.each(function(index, node) {
  var parentNode = node.parentNode;
  //由于现在的IE不支持直接对svg标签node取内容,所以需要在当前标签外面套一层div,通过外层div的innerHTML属性来获取
  var tempNode = document.createElement('div');
  tempNode.appendChild(node);
  var svg = tempNode.innerHTML;
  var canvas = document.createElement('canvas');
  //转换
  canvg(canvas, svg);
  parentNode.appendChild(canvas);
 });
}

第二步:将Glyphicons字体图标转换为Canvas。若项目中未使用Glyphicons字体,可跳过此步骤。

Glyphicons字体图标转换逻辑


glyphicons2canvas: function(targetElem, fontClassName, fontFamilyName) {
 var iconElems = targetElem.find('.' + fontClassName);
 iconElems.each(function(index, inconNode) {
  var fontSize = $(inconNode).css("font-size");
  var iconColor = $(inconNode).css("color");
  var styleContent = $(inconNode).attr('style');
  //去掉"px"
  fontSize = fontSize.replace("px", "");
  var charCode = getCharCodeByGlyphiconsName(iconName);
  var myCanvas = document.createElement('canvas');
  //把canva宽高各增加2是为了显示图标完整
  myCanvas.width = parseInt(fontSize) + 2;
  myCanvas.height = parseInt(fontSize) + 2;
  myCanvas.style = styleContent;
  var ctx = myCanvas.getContext('2d');
  //设置绘图内容的颜色
  ctx.fillStyle = iconColor;
  //设置绘图的字体大小以及font-family的名字
  ctx.font = fontSize + 'px ' + fontFamilyName;
  ctx.fillText(String.fromCharCode(charCode), 1, parseInt(fontSize) + 1);
  $(inconNode).replaceWith(myCanvas);
 });
}
//根据glyphicons/glyphicon图标的类名获取到对应的char code
getCharCodeByGlyphiconsName: function(iconName) {
 switch (iconName) {
 case("glyphicons-resize-full"):
  return "0xE216";
 case ("glyphicons-chevron-left"):
  return "0xE225";
 default:
  return "";
 }
}

第三步:执行HTML转Canvas、转图片,最后生成PDF的完整流程。

HTML至PDF的最终生成代码


html2canvas($("#myExportArea"), {
 onrendered: function(canvas) {
  var imgData = canvas.toDataURL('image/jpeg');
  var img = new Image();
  img.src = imgData;
  //根据图片的尺寸设置pdf的规格,要在图片加载成功时执行,之所以要*0.225是因为比例问题
  img.onload = function() {
   //此处需要注意,pdf横置和竖置两个属性,需要根据宽高的比例来调整,不然会出现显示不完全的问题
   if (this.width > this.height) {
    var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225]);
   } else {
    var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225]);
   }
   doc.addImage(imgData, 'jpeg', 0, 0, this.width * 0.225, this.height * 0.225);
   //根据下载保存成不同的文件名
   doc.save('report_pdf_' + new Date().getTime() + '.pdf');
  }
 },
 background: "#fff",
 //这里给生成的图片默认背景,不然的话,如果你的html根节点没设置背景的话,会用黑色填充。
 allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas
});

尽管最终勉强满足了客户需求,但生成的PDF清晰度略低于原生截图。受限于当前技术水平,暂仅能采用此方法,如有更优方案,欢迎交流。

以上纯JS实现HTML转PDF的实例分享完毕,希望能为开发者提供参考,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章