纯前端实现网页截图导出:Canvas、字体加载与跨域图片
把页面区域导出一张图片,看起来是 canvas 画一下就结束,实际最容易遇到三类问题:截出来是白图、文字字体不对、跨域图片直接缺失。这篇文章按导出流程逐项处理。
一、先拿到稳定的绘制尺寸
截图前先读目标节点的布局尺寸,再乘设备像素比,避免高分屏导出后模糊:
const rect = target.getBoundingClientRect();
const scale = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.round(rect.width * scale);
canvas.height = Math.round(rect.height * scale);
ctx.scale(scale, scale);
把画布坐标统一到 CSS 像素,后面的绘制代码就不会到处乘缩放倍率。
二、等字体真正可用
如果页面刚加载就截图,字体可能还在下载,Canvas 会退回默认字体。绘制文本前显式等待:
await document.fonts.ready;
await document.fonts.load('16px "Example Sans"');
自定义字体需要先通过 CSS 声明,fonts.load 才能按字体族和字重找到资源。
三、控制绘制顺序
页面 DOM 不能直接复制进 Canvas,需要按自己的结构绘制背景、面板和文本。先铺背景,再画卡片,最后画文字,顺序错了就会被后一层盖住。文本要自己处理换行、行高和省略号,不能依赖 CSS 布局。
四、跨域图片
绘制外域图片时先设置 crossOrigin,并确保图片服务器返回允许跨域的响应头。否则画布会被污染,调用 toBlob 或 toDataURL 时抛安全错误。处理方式是在加载时统一走同源代理,或缺图时使用占位资源。
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = url;
await image.decode();
五、导出与释放
使用 canvas.toBlob 生成 Blob,再用 URL.createObjectURL 下载更省内存。导出完成后 revokeObjectURL,避免大图长期占内存。按钮要防重复点击,并在导出期间显示明确状态。
六、可测性
把尺寸计算、换行和资源加载拆成独立函数,分别测试。视觉结果可以用固定数据生成基准截图比较,避免每次改字体或布局都靠肉眼检查。
七、小结
网页截图的关键是尺寸一致、字体已加载、绘制顺序正确、跨域资源可控、Blob 用完释放。把这几个边界处理清楚,导出功能才稳定。
- 点赞
- 收藏
- 关注作者
评论(0)