xChar
·3 months ago

起因

为了方便分享网页特定元素,我们就需要在前端进行网页截图。
优势:

  1. 长页面无需手机支持长截图
  2. 仅针对特定元素截取,节约空间&防止隐私泄露
  3. 可在分享时展示更适合分享的格式/信息

正文

简单一点

于是便找到了html2canvas这个项目。
它可以将页面元素转化为一个canvas,于是就可以使用.toDataURL()方法.toBlob()方法导出为图像。

  1. 为元素设置id
<div id="to_capture">
  <p>There is sth. to capture.</p>
</div>
  1. html2canvas获取该元素:
const htmlId = 'to_capture'

const PicDom = document.getElementById(htmlId);
const url = html2canvas(shareContent, opts).then(function (canvas) {
  const context = canvas.getContext("2d");
  // .toDataURL 支持两个参数
  // 第一个是保存的格式:image/png (默认)  image/webp  image/jpeg
  // 第二个是图像质量 (0 到 1 的数字):webp/jpeg 时可用
  const img = canvas.toDataURL('image/webp');
});
  1. 下载:
function DlLink(link: string, name?: string) {
  const a = document.createElement("a");
  a.href = link;
  a.download = name || "文件名.png";
  a.click();
  a.remove();
}
DlLink(url,'测试.webp')

优化一下

图片太糊?试着使浏览器将元素放大一下。

比如我们要放大 2 倍,则设置

const scale = 2;
const rcScale = 1 / scale; // 即 0.5

将 获取 ID + 放大 独立成一个函数

Link

赋予要截图的元素一个样式

这里的scale(0.5)中的0.5rcScale的值。

.tmp_capture {
  transform: scale(0.5);
  img {
    display: initial; /* 据说可以解决图片文字/图标向下偏移的问题,但我这貌似没用 */
  }
}
<div class="tmp_capture" id="to_capture"></div>

当然,这个方案会改变实际的元素渲染大小,所以你可以利用 Vue/React 等动态赋予 class,同时显现分享专属信息。

题外话 (VitePress 的 table 样式导致的问题)

由于.vp-doc给 table 的样式含display: block;,导致即使表内容没有占满整行也会实际占用,这在缩小后更明显,使得生成图片有大白边 (无内容),于是我们给tmp_capture一个display: inline-table;覆盖掉即可。

看看成品

这是AniClip项目的开发日志,相关文件如下:

html2pic.ts
common.ts
s.vue68-8488-138312 之后style 标签

体验AniClip分享功能 (请选择展开表格,点击保存为图片)

参考/引用/延伸阅读

【基于 html2canvas 实现网页保存为图片及图片清晰度优化】分享自 @SegmentFault

此文由 Mix Space 同步更新至 xLog
原始链接为 https://xrzyun.eu.org/posts/devlogs/capture-for-webs-using-html2canvas


Loading comments...