
项目做完了,用到了html2canvas,虽然代码是AI写的,但是还是碰到了很多不好解决的问题,不过总归是解决了,现在回过头静下心来认真学习一下 html2canvas,以及总结一下各类问题的解决方法。
一、html2canvas项目概述与核心定位
html2canvas 是一个 JavaScript HTML 渲染器,允许直接在用户浏览器中对网页或页面局部进行"截图"。该库由 Niklas von Hertzen 开发并维护,整个图像在客户端浏览器中生成,不需要服务器端渲染支持。
核心定位:基于 DOM 和样式信息构建页面表示,而非执行真正的屏幕截图。因此,其结果可能与真实视觉呈现存在差异。
项目源码托管于 GitHub:
- 仓库地址:https://github.com/niklasvh/html2canvas
- 克隆地址:
git clone git://github.com/niklasvh/html2canvas.git
基本示例
以下代码展示了最简使用方式,将 ID 为 capture 的 DOM 元素渲染为 canvas 并追加到页面中:
<div id="capture" style="padding: 10px; background: #f5da55">
<h4 style="color: #000;">Hello world!</h4>
</div>
html2canvas(document.querySelector("#capture")).then((canvas) => {
document.body.appendChild(canvas);
});
该库经过 gzip 压缩后体积约为 45KB,可通过 npm 或 Yarn 安装,也可直接下载 html2canvas.js 或 html2canvas.min.js 使用。
二、html2canvas的安装与引入
通过 npm 安装
npm install --save html2canvas
import html2canvas from "html2canvas";
通过 Yarn 安装
yarn add html2canvas
浏览器直接引入
可直接下载 html2canvas.js 或 html2canvas.min.js 文件通过 <script> 标签引入。
三、html2canvas的工作原理
html2canvas 的工作机制并非传统意义上的截图,而是一个 DOM 遍历与重建过程:
- DOM 遍历:脚本遍历当前页面加载的 DOM 树,收集所有元素及其应用样式;
- 信息提取:读取元素的样式属性,构建页面的内部表示;
- Canvas 绘制:基于收集到的信息在
<canvas>上绘制图像。
注意注意! 由于每个 CSS 属性都需要手动编码支持,html2canvas 永远无法实现完整的 CSS 支持,仅覆盖最常用的属性,所有会出现生成的截图和元素DOM样式不一样的情况。
四、html2canvas实用场景与实战案例
场景 1:社交媒体分享海报生成
这是 html2canvas 最常见的使用场景之一。将页面中的海报 DOM 区域转换为图片,供用户长按保存或分享。
async function generateSharePoster() {
const posterElement = document.querySelector(".poster-container");
const canvas = await html2canvas(posterElement, {
scale: 2, // 高清输出
useCORS: true, // 允许跨域图片
backgroundColor: null, // 透明背景
logging: false, // 关闭调试日志
});
// 转换为图片并触发下载
const imgData = canvas.toDataURL("image/png");
const link = document.createElement("a");
link.href = imgData;
link.download = "share-poster.png";
link.click();
}
关键技巧:
- 海报中的头像、背景图等素材需确保跨域可访问,或配置
useCORS: true; - 若海报在页面上默认隐藏(如
display: none),需在onclone回调中将其设为可见。
场景 2:网页内容导出为 PDF
结合 jsPDF 库,将网页内容导出为 PDF 文档,适用于报表、发票、简历等场景。
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
async function exportToPDF() {
const element = document.getElementById("print-area");
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true,
onclone: (doc) => {
// 在克隆文档中隐藏打印按钮,不影响原始页面
const printBtn = doc.getElementById("print-button");
if (printBtn) printBtn.style.visibility = "hidden";
},
});
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF("p", "mm", "a4");
const imgWidth = 210; // A4 宽度 mm
const imgHeight = (canvas.height * imgWidth) / canvas.width;
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
pdf.save("document.pdf");
}
分页处理长页面:当内容高度超过单页 A4 时,需要计算分页位置并逐页添加。
function generateMultiPagePDF(element) {
return html2canvas(element, { scale: 2 }).then((canvas) => {
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF("p", "mm", "a4");
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgWidth = canvas.width;
const imgHeight = canvas.height;
const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight);
let heightLeft = imgHeight * ratio;
let position = 0;
// 第一页
pdf.addImage(
imgData,
"PNG",
0,
position,
imgWidth * ratio,
imgHeight * ratio,
);
heightLeft -= pdfHeight;
// 后续分页
while (heightLeft > 0) {
position = heightLeft - imgHeight * ratio;
pdf.addPage();
pdf.addImage(
imgData,
"PNG",
0,
position,
imgWidth * ratio,
imgHeight * ratio,
);
heightLeft -= pdfHeight;
}
pdf.save("multi-page.pdf");
});
}
场景 3:地图截图与数据可视化导出
在地图应用(如 OpenLayers、Leaflet)或 ECharts 图表中,用户常需要导出当前视图。
// OpenLayers 地图导出示例
map.once("rendercomplete", function () {
const target = map.getViewport();
html2canvas(target, {
ignoreElements: function (element) {
// 过滤掉地图控件(缩放按钮、版权信息等)
return element.className.indexOf("ol-control") !== -1;
},
logging: false,
useCORS: true,
}).then(function (canvas) {
canvas.toBlob(function (blob) {
saveAs(blob, "map.png");
});
});
});
注意:html2canvas 只能截取浏览器视口中可见的内容,超出视口的部分需要额外处理。
场景 4:电子签名与水印叠加
在生成截图后,可在 canvas 上叠加水印或签名信息。
async function generateWithWatermark() {
const element = document.querySelector(".document-content");
const canvas = await html2canvas(element, { scale: 2 });
const ctx = canvas.getContext("2d");
// 添加文字水印
ctx.font = "20px Arial";
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.rotate(-Math.PI / 6);
ctx.fillText("CONFIDENTIAL", 100, 200);
// 保存
const link = document.createElement("a");
link.download = "watermarked.png";
link.href = canvas.toDataURL();
link.click();
}
场景 5:差异化导出(打印版与屏幕版不同内容)
利用 onclone 钩子,可以在不影响原始页面的情况下,为导出内容添加或移除元素。
html2canvas(element, {
onclone: (clonedDoc) => {
// 在导出版本中移除屏幕专属元素
const screenOnly = clonedDoc.getElementsByClassName("screen-only");
Array.from(screenOnly).forEach((el) => el.remove());
// 在导出版本中显示打印专属元素
const printOnly = clonedDoc.getElementsByClassName("print-only");
Array.from(printOnly).forEach((el) => (el.style.display = "block"));
},
}).then((canvas) => {
// 处理导出...
});
五、html2canvas配置选项详解与深度用法
html2canvas 提供丰富的配置选项以控制渲染行为,完整列表如下:
| 配置项 | 默认值 | 说明 |
|---|---|---|
allowTaint | false | 是否允许跨域图像污染 canvas |
backgroundColor | #ffffff | canvas 背景色;若 DOM 中未指定则使用此值,设为 null 可透明 |
canvas | null | 用作绘制基础的现有 <canvas> 元素 |
foreignObjectRendering | false | 浏览器支持时是否使用 ForeignObject 渲染 |
imageTimeout | 15000 | 图像加载超时(毫秒),设为 0 禁用超时 |
ignoreElements | (element) => false | 断言函数,返回 true 的元素将从渲染中移除 |
logging | true | 是否启用调试日志 |
onclone | null | 文档被克隆用于渲染时的回调函数,可修改渲染内容而不影响原始源文档 |
proxy | null | 用于加载跨域图像的代理 URL;留空则不加载跨域图像 |
removeContainer | true | 是否清理 html2canvas 临时创建的克隆 DOM 元素 |
scale | window.devicePixelRatio | 渲染缩放比例,默认为浏览器设备像素比 |
useCORS | false | 是否尝试使用 CORS 从服务器加载图像 |
width | 元素宽度 | canvas 宽度 |
height | 元素高度 | canvas 高度 |
x | 元素 x 偏移 | canvas 裁剪 x 坐标 |
y | 元素 y 偏移 | canvas 裁剪 y 坐标 |
scrollX | 元素 scrollX | 渲染元素时使用的 x 滚动位置(例如元素使用 position: fixed 时) |
scrollY | 元素 scrollY | 渲染元素时使用的 y 滚动位置 |
windowWidth | Window.innerWidth | 渲染时使用的窗口宽度,可能影响媒体查询 |
windowHeight | Window.innerHeight | 渲染时使用的窗口高度 |
5.1 scale:清晰度控制的核心参数
scale 是控制输出质量最关键的参数。默认值为 window.devicePixelRatio(Retina 屏通常为 2,普通屏为 1)。
问题:在高清屏上若未正确处理 DPR,生成的图片会显得模糊。
解决方案:
// 方案 1:显式设置 scale(推荐)
html2canvas(element, {
scale: 2, // 或 3,根据需求平衡清晰度与性能
});
// 方案 2:使用自定义 canvas 实现更精细控制
const scaleBy = 2;
const canvas = document.createElement("canvas");
canvas.width = element.offsetWidth * scaleBy;
canvas.height = element.offsetHeight * scaleBy;
canvas.style.width = element.offsetWidth + "px";
canvas.style.height = element.offsetHeight + "px";
const ctx = canvas.getContext("2d");
ctx.scale(scaleBy, scaleBy);
html2canvas(element, {
canvas: canvas,
scale: 1, // 使用外部 canvas 时,内部 scale 设为 1
}).then((canvas) => {
// canvas 已经是高分辨率输出
});
性能权衡:
| Scale 值 | 输出质量 | 内存占用 | 适用场景 |
|---|---|---|---|
| 1 | 普通 | 低 | 快速预览 |
| 2 | 清晰 | 中 | 大多数生产环境 |
| 3+ | 极清 | 高 | 打印级 PDF、高 PPI 设备 |
注意:
scale提升会按平方级增加 Canvas 像素总量(宽度 × 高度 × scale²),可能导致内存溢出,尤其是在移动端。
5.2 ignoreElements 与 data-html2canvas-ignore:元素过滤
用于排除不需要渲染的元素,如导航栏、广告、操作按钮等。
方式 1:使用属性(推荐,性能更好)
<div data-html2canvas-ignore>这段内容不会出现在截图中</div>
方式 2:使用函数过滤
html2canvas(document.body, {
ignoreElements: (element) => {
// 排除特定类名的元素
return (
element.classList.contains("no-export") ||
element.classList.contains("ad-banner") ||
element.tagName === "BUTTON"
);
},
});
实际案例:在地图截图中过滤控件元素。
html2canvas(document.getElementById("map"), {
ignoreElements: (el) =>
el.classList.contains("gmnoprint") || // Google Maps 打印控件
el.classList.contains("gm-style-cc") || // 版权信息
el.tagName === "BUTTON",
});
5.3 onclone:DOM 预处理神器
onclone 在文档克隆完成后、渲染开始前触发,是修改渲染内容而不影响原始页面的唯一安全时机。
常见用法:
html2canvas(document.body, {
onclone: (clonedDoc) => {
// 1. 移除临时元素
const banner = clonedDoc.querySelector(".temporary-banner");
if (banner) banner.parentNode.removeChild(banner);
// 2. 修改文本内容
const title = clonedDoc.querySelector("h1");
if (title) title.textContent = "截图专用标题";
// 3. 调整样式
const chart = clonedDoc.querySelector(".echarts-container");
if (chart) {
chart.style.transform = "scale(1)"; // 取消缩放
chart.style.width = "800px"; // 固定宽度
}
// 4. 显示隐藏元素
const hidden = clonedDoc.querySelector(".hidden-for-export");
if (hidden) hidden.style.display = "block";
// 5. 调试技巧:将克隆文档挂载到全局以便在 DevTools 中检查
window.clonedDoc = clonedDoc;
},
}).then((canvas) => {
document.body.appendChild(canvas);
});
重要注意:onclone 中修改的是克隆文档,原始页面 DOM 完全不受影响。
5.4 useCORS 与 allowTaint:跨域图像处理
这是最容易混淆的两个配置项,必须正确理解其区别:
| 配置项 | 作用 | 适用场景 |
|---|---|---|
useCORS: true | 尝试通过 CORS 加载跨域图片(给 <img> 添加 crossOrigin="anonymous") | 图片服务器支持 CORS 响应头 |
allowTaint: true | 允许跨域图片渲染到 canvas,但会污染 canvas | 仅查看,不需要导出图片 |
两者同时 true | useCORS 优先,若 CORS 失败则回退到 allowTaint | 不推荐,可能导致不一致行为 |
正确配置组合:
// 场景 A:需要导出图片,图片服务器支持 CORS
html2canvas(element, {
useCORS: true,
allowTaint: false, // 或不设置(默认 false)
});
// 场景 B:仅展示截图,不需要导出
html2canvas(element, {
allowTaint: true, // canvas 被污染,无法 toDataURL()
});
// 场景 C:图片服务器不支持 CORS,但需要导出
// 必须使用代理服务器
html2canvas(element, {
proxy: "https://your-proxy-server.com/proxy",
});
图片元素要求:使用 useCORS 时,需确保 <img> 标签也设置 crossorigin 属性。
<img crossorigin="anonymous" src="https://cdn.example.com/image.jpg" />
5.5 foreignObjectRendering:SVG 渲染模式
当设为 true 时,html2canvas 会利用浏览器的 ForeignObject 特性来渲染 SVG,可能提升某些场景下的渲染质量,但存在已知问题:
- 不支持连字字体(如 Google Material Icons 可能显示为原始文本而非图标)
- 不支持
opacity: 0的元素捕获 - 速度可能比默认模式更慢
建议:仅在特定 SVG 渲染问题无法解决时尝试开启。
5.6 scrollX / scrollY / windowWidth / windowHeight:处理固定定位与滚动
当截图元素使用了 position: fixed 或页面存在滚动时,需要正确设置这些参数。
// 截图前将页面滚动到顶部,避免截断
window.scrollTo(0, 0);
document.body.scrollTop = document.documentElement.scrollTop = 0;
html2canvas(element, {
scrollX: 0,
scrollY: 0,
windowWidth: document.documentElement.scrollWidth,
windowHeight: document.documentElement.scrollHeight,
});
5.7 排除特定元素
如需排除某些元素不参与渲染,可为这些元素添加 data-html2canvas-ignore 属性,html2canvas 将自动跳过它们。
六、html2canvas支持的 CSS 特性
html2canvas已支持的 CSS 属性
以下属性已被 html2canvas 支持:
- background
background-clip(不支持text)background-colorbackground-image:url()、linear-gradient()、radial-gradient()background-originbackground-positionbackground-size
- border
border-colorborder-radiusborder-styleborder-width
- 布局与盒模型:
bottom、box-sizing、content、display、flex、float、height、left、margin、max-height、max-width、min-height、min-width、padding、position、right、top、width、z-index - 字体与文本:
color、font-family、font-size、font-style、font-variant、font-weight、letter-spacing、line-break、text-align、text-decoration(含text-decoration-color、text-decoration-line;text-decoration-style仅支持solid)、text-shadow、text-transform、white-space、word-break、word-spacing、word-wrap、overflow-wrap、webkit-text-stroke - 列表:
list-style-image、list-style-position、list-style-type - 其他:
opacity、overflow、paint-order、transform(有限支持)、visibility
不支持的 CSS 属性
以下属性目前不支持:
background-blend-modeborder-imagebox-decoration-breakbox-shadowfilterfont-variant-ligaturesmix-blend-modeobject-fitrepeating-linear-gradient()writing-modezoom
七、跨域图像与代理
同源策略限制
html2canvas 无法绕过浏览器的内容安全策略限制。绘制来自当前页面源(origin)之外的图像会污染(taint)canvas,被污染的 canvas 将无法再被读取。因此,html2canvas 会在应用图像前检查其是否会污染 canvas。若 allowTaint 设为 false,跨域图像将不会被绘制。
解决方案:代理
如需加载跨域图像,可使用代理服务器将图像转发到与页面相同的源。官方目前提供以下代理实现:
- node.js 代理
通过配置 proxy 选项指向代理服务地址即可启用。
八、浏览器兼容性
html2canvas 支持以下浏览器(需 Promise polyfill):
- Firefox 3.5+
- Google Chrome
- Opera 12+
- IE9+
- Edge
- Safari 6+
由于库的实现严重依赖浏览器环境,不适合在 Node.js 中使用。
九、常见问题与解决方案
9.1 图像模糊与分辨率问题
现象:在 Retina 屏幕或高 DPI 设备上,生成的图片模糊不清。
原因:html2canvas 默认使用 window.devicePixelRatio 作为 scale,但在某些情况下未能正确识别或应用。
解决方案:
// 显式设置 scale
html2canvas(element, {
scale: 2, // 或 window.devicePixelRatio
useCORS: true,
logging: false,
});
// 对于打印级 PDF,可设置更高 scale
html2canvas(element, {
scale: 3,
dpi: 192, // 可选,明确设置每英寸点数
});
注意:scale 提升会线性增加内存占用,移动端需谨慎使用。
9.2 跨域图片无法显示 / 空白
现象:截图中跨域图片显示为空白,控制台报错。
解决方案:
- 首选方案:确保图片服务器返回
Access-Control-Allow-Origin响应头,并配置useCORS: true; - 备选方案:使用代理服务器转发图片;
- 不推荐:
allowTaint: true仅适用于不需要导出图片的场景。
// 正确配置
html2canvas(element, {
useCORS: true,
allowTaint: false,
});
// 同时给 img 标签添加 crossorigin 属性
// <img crossorigin="anonymous" src="..." />
9.3 iOS 15 系统字体导致渲染失败
现象:在 iOS 15 设备上,html2canvas 生成空白图片或崩溃。
原因:iOS 15 中 -apple-system 字体会导致 canvas 渲染异常。
解决方案:在根节点显式声明字体,避免使用 -apple-system。
#app {
font-family:
Helvetica, Tahoma, Arial, "PingFang SC", "Hiragino Sans GB", "Heiti SC",
STXihei, "Microsoft YaHei", SimHei;
}
9.4 text-overflow: ellipsis 不生效
现象:CSS 中设置了 text-overflow: ellipsis,但生成的图片中文字未被截断显示省略号。
原因:html2canvas 对该属性的支持有限。
解决方案:
- 手动截断文本,使用 JavaScript 计算字符长度并添加
...; - 或使用固定宽度的容器配合
overflow: hidden。
9.5 transform: scale() 导致文字重叠
现象:父元素设置了 transform: scale(),截图中文字重叠或错位。
原因:html2canvas 在处理缩放变换时,字体大小未按比例调整。
解决方案:在 onclone 中将缩放恢复为 1,或手动调整字体大小。
html2canvas(element, {
onclone: function (documentClone) {
const box = documentClone.getElementById("export-box");
if (box) box.style.transform = "scale(1)";
},
});
9.6 SVG 图标通过 <use> 引用时不显示
现象:使用 <symbol> + <use> 方式引用的 SVG 图标在截图中消失。
原因:html2canvas 单独解析遇到的 <svg> 元素,无法处理 <use> 的外部引用。
解决方案:在 onclone 中将 <use> 替换为内联 SVG 内容。
html2canvas(element, {
onclone: (doc) => {
const uses = doc.querySelectorAll("use");
uses.forEach((use) => {
const symbolId =
use.getAttribute("href") || use.getAttribute("xlink:href");
const symbol = doc.querySelector(symbolId);
if (symbol) {
const svg = document.createElementNS(
"http://www.w3.org/2000/svg",
"svg",
);
svg.innerHTML = symbol.innerHTML;
use.parentNode.replaceChild(svg, use);
}
});
},
});
9.7 字体加载失败导致文字错位
现象:自定义字体(如 Google Fonts、阿里巴巴普惠体)未正确加载,截图中使用回退字体,导致排版错乱。
原因:html2canvas 在渲染时会重新下载字体,若字体未缓存或网络较慢,会使用 fallback 字体。
解决方案:
- 确保字体在调用 html2canvas 前已完全加载;
- 使用
document.fonts.ready等待字体加载完成; - 将字体文件转为 Base64 内联到 CSS 中。
await document.fonts.ready; // 等待所有字体加载完成
const canvas = await html2canvas(element, { scale: 2 });
9.8 Tailwind CSS v4 oklch() 颜色解析失败
现象:使用 Tailwind CSS v4 时,html2canvas 报错 Attempting to parse an unsupported color function "oklch"。
原因:Tailwind v4 默认使用 oklch() 颜色格式,html2canvas 1.4.1 尚未支持。
临时解决方案:
- 在 Tailwind 配置中回退到传统颜色格式;
- 或等待官方支持
oklch()和oklab()的更新。
9.9 阿拉伯语 / 希伯来语等 RTL 文字渲染错乱
现象:RTL(从右到左)语言文本字符纠缠、方向错误。
原因:html2canvas 对 Unicode 双向文本算法(Bidi)的支持不完善。
解决方案:
- 手动设置文本方向;
- 或使用专门的 RTL 处理库预处理文本。
9.10 截图被截断 / 只显示部分页面
现象:长页面截图只显示了视口内的内容,下方内容被截断。
原因:html2canvas 默认只渲染传入元素的可见区域。
解决方案:
// 方案 1:设置窗口尺寸为元素完整尺寸
html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
scrollX: 0,
scrollY: 0,
});
// 方案 2:截图前将页面滚动到顶部
window.scrollTo(0, 0);
document.body.scrollTop = document.documentElement.scrollTop = 0;
9.11 变量字体(Variable Fonts)font-variation-settings 不支持
现象:使用变量字体的自定义轴设置时,html2canvas 只渲染默认字重。
原因:html2canvas 尚未实现对 font-variation-settings 的解析。
解决方案:使用标准字体族替代变量字体,或预先将文字转为图片。
十、PDF 生成专题:深度问题与解决方案
10.1 字体颜色不一致 / CSS 样式异常
现象:使用 html2canvas + jsPDF 生成 PDF 时,部分文字颜色与页面显示不一致,或某些 CSS 样式丢失。
原因:html2canvas 在克隆 DOM 时,某些动态计算的样式(如通过 JavaScript 设置的样式、CSS 变量)可能未被正确继承。
解决方案:利用 onclone 在渲染前强制修正样式。
html2canvas(element, {
scale: 2,
onclone: (clonedDoc) => {
// 强制设置字体颜色,确保一致性
const textElements = clonedDoc.querySelectorAll(
"p, span, h1, h2, h3, h4, h5, h6",
);
textElements.forEach((el) => {
// 获取计算样式并强制内联
const computedStyle = window.getComputedStyle(el);
el.style.color = computedStyle.color;
el.style.fontFamily = computedStyle.fontFamily;
el.style.fontSize = computedStyle.fontSize;
el.style.lineHeight = computedStyle.lineHeight;
});
// 处理特定组件的样式异常
const cards = clonedDoc.querySelectorAll(".info-card");
cards.forEach((card) => {
card.style.backgroundColor = "#ffffff";
card.style.border = "1px solid #e0e0e0";
});
},
}).then((canvas) => {
// 生成 PDF...
});
10.2 Bootstrap 进度条文字显示异常
现象:PDF / 分享图片中,Bootstrap 的 .progress-stacked 进度条上的文字换行挤在一起,或被裁剪消失。
原因分析:
Bootstrap 的 .progress-stacked 依赖 overflow: hidden 来裁剪进度条色块,但 html2canvas 在将 DOM 渲染成 canvas 时,对 overflow: hidden + flexbox 的处理与浏览器不一致,导致文字被裁掉或强制换行。
此外,html2pdf.js 的 onclone 回调操作的是一个沙箱副本 DOM,而 html2canvas 实际渲染的是另一份拷贝,两者不是同一个对象,所以在 onclone 里的任何 DOM 修改都不会反映到最终渲染结果上。
解决方案:在调用 html2canvas /
html2pdf
之前,直接操作页面真实 DOM,将 .progress-stacked 替换成用绝对定位实现的自定义色块+文字结构,渲染完成后再还原。绝对定位完全脱离 overflow: hidden 的影响,是 html2canvas 能稳定渲染的布局方式。
async function exportWithProgressBar(element) {
// 1. 备份原始 HTML
const originalHTML = element.innerHTML;
// 2. 替换进度条为绝对定位版本(操作真实 DOM)
const progressBars = element.querySelectorAll(".progress-stacked");
progressBars.forEach((bar) => {
const width = bar.style.width || "50%";
const label = bar.querySelector(".progress-label")?.textContent || "";
// 创建绝对定位的替代结构
const replacement = document.createElement("div");
replacement.className = "progress-absolute-wrapper";
replacement.style.cssText = `
position: relative;
width: 100%;
height: 20px;
background: #e9ecef;
border-radius: 4px;
`;
replacement.innerHTML = `
<div style="
position: absolute;
left: 0; top: 0;
width: ${width};
height: 100%;
background: #0d6efd;
border-radius: 4px;
"></div>
<span style="
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%);
font-size: 12px;
color: #333;
white-space: nowrap;
">${label}</span>
`;
bar.parentNode.replaceChild(replacement, bar);
});
try {
// 3. 执行截图
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true,
});
// 4. 生成 PDF 或图片
const imgData = canvas.toDataURL("image/png");
// ... 使用 jsPDF 生成 PDF
return imgData;
} finally {
// 5. 还原原始 DOM(无论成功失败都执行)
element.innerHTML = originalHTML;
}
}
关键要点:
- 不要依赖
onclone来修改进度条结构,因为 html2pdf.js 和 html2canvas 使用的克隆文档是独立的; - 绝对定位是 html2canvas 最稳定的布局方式,避免使用
overflow: hidden+ flexbox 的组合; - 操作真实 DOM 后务必备份并还原,避免影响用户界面。
十一、使用建议与注意事项
- 实验性状态:该脚本仍处于非常实验性的阶段,不建议在生产环境中使用或基于此构建应用,因为未来可能会有重大变更。
- Promise 支持:html2canvas 依赖 Promise,如需兼容旧版浏览器,请在引入 html2canvas 前加载如
es6-promise之类的 polyfill。 - 插件内容:脚本不渲染插件内容,如 Flash 或 Java Applet。
- Tainted Canvas:页面中已有的
<canvas>元素若被跨域内容污染,html2canvas 将无法读取它们。 - 性能优化:处理大型 DOM 时,建议:
- 使用
ignoreElements过滤非必要元素; - 缩小截图范围,避免
document.body; - 关闭
logging以减少控制台输出开销。
- 使用







