html2canvas实现浏览器截图的原理(包含源码分析的通⽤⽅法)
DevUI是⼀⽀兼具设计视⾓和⼯程视⾓的团队,服务于华为云平台和华为内部数个中后台系统,服务于设计师和前端⼯程师。
官⽅⽹站:
Ng组件库:(欢迎Star)
官⽅交流:添加DevUI⼩助⼿(devui-official)
DevUIHelper插件:DevUIHelper-LSP(欢迎Star)
引⾔
有时⽤户希望将我们的报表页⾯分享到其他的渠道,⽐如邮件、PPT等,每次都需要⾃⼰截图,⼀是很⿇烦,⼆是截出来的图⼤⼩不⼀。
有没有办法在页⾯提供⼀个下载报表页⾯的功能,⽤户只需要点击按钮,就⾃动将当前的报表页⾯以图
⽚形式下载下来呢?
html2canvas库就能帮我们做到,⽆需后台⽀持,纯浏览器实现截图,即使页⾯有滚动条也是没问题的,截出来的图⾮常清晰。
这个库的维护时间⾮常长,早在2013年9⽉8⽇它就发布了第⼀个版本,⽐Vue的第⼀个版本(2013年12⽉8⽇)还要早。
截⽌到今天2020年12⽉18⽇,html2canvas库在github已经有22.3k star,在npm的周下载量也有506k,⾮常了不起!
上⼀次提交是在2020年8⽉9⽇,可见作者依然在很热情地维护着这个库,⽽且⽤TypeScript重构过,不过这个库的作者⾮常保守,哪怕已经持续不断地维护了7年,他在README⾥依然提到这个库⽬前还在实验阶段,不建议在⽣产环境使⽤。
事实上我很早就将这个库⽤在了⽣产环境,这篇⽂章就来分析下这个神奇和了不起的JavaScript库,看看它是怎么实现浏览器端截图的。
1 如何使⽤
希澈韩庚在介绍html2canvas的原理之前,先来看看怎么使⽤它,使⽤起来真的⾮常简单,⼏乎是1分钟上⼿。
使⽤html2canvas只要以下3步:
1. 安装
2. 引⼊
3. 调⽤
Step 1: 安装
npm i html2canvas
许晴结婚了吗
Step 2: 引⼊
随便在⼀个现代框架的⼯程项⽬中引⼊html2canvas
import html2canvas from 'html2canvas';
Step 3: 截图并下载
html2canvas就是⼀个函数,在页⾯渲染完成之后直接调⽤即可。
视图渲染完成的事件:
1. Angular的ngAfterViewInit⽅法励志奖学金申请书范文
2. React的componentDidMount⽅法
3. Vue的mounted⽅法
可以只传⼀个参数,就是你要截图的DOM元素,该函数返回⼀个Promise对象,在它的then⽅法中可以获取到绘制好的canvas对象,通过调⽤canvas对象的toDataURL⽅法就可以将其转换成图⽚。
拿到图⽚的URL之后,我们可以
1. 将其放到<img>标签的src属性中,让其显⽰在⽹页中;
2. 也可以将其放到<a>标签的href属性中,将该图⽚下载到本地磁盘中。
我们选择后者。
html2canvas(document.querySelector('.main')).then(canvas => {
const link = ateElement('a'); // 创建⼀个超链接对象实例
八月再见九月你好的图片const event = new MouseEvent('click'); // 创建⼀个⿏标事件的实例
link.download = 'Button.png'; // 设置要下载的图⽚的名称
link.href = DataURL(); // 将图⽚的URL设置到超链接的href中
link.dispatchEvent(event); // 触发超链接的点击事件
});寒窑赋原文
是不是⾮常简单?
参数
我们再来⼤致看⼀眼它的API,该函数的签名如下:
html2canvas(element: HTMLElement, options: object): Promise<HTMLCanvasElement>
options对象可选的值如下:
Name Default Description
allowTaint false是否允许跨域图像污染画布
backgroundColor#ffffff画布背景颜⾊,如果在DOM中没有指定,设置“null”(透明)
canvas null使⽤现有的“画布”元素,⽤来作为绘图的基础
foreignObjectRendering false是否使⽤ForeignObject渲染(如果浏览器⽀持的话)
imageTimeout15000加载图像的超时时间(毫秒),设置为“0”以禁⽤超时
ignoreElements(element) => false从呈现中移除匹配元素
logging true为调试⽬的启⽤⽇志记录
onclone null回调函数,当⽂档被克隆以呈现时调⽤,可以⽤来修改将要呈现的内容,⽽不影响原始源⽂档。
proxy null⽤来加载跨域图⽚的代理URL,如果设置为空(默认),跨域图⽚将不会被加载
removeContainer true是否清除html2canvas临时创建的克隆DOM元素
scale window.devicePixelRatio⽤于渲染的缩放⽐例,默认为浏览器设备像素⽐
useCORS false是否尝试使⽤CORS从服务器加载图像
width Element width canvas的宽度
height Element height canvas的⾼度
x Element x-offset canvas的x轴位置
y Element y-offset canvas的y轴位置
scrollX Element scrollX渲染元素时使⽤的x轴位置(例如,如果元素使⽤position: fixed)
scrollY Element scrollY渲染元素时使⽤的y轴位置(例如,如果元素使⽤position: fixed)
windowWidth Window.innerWidth渲染元素时使⽤的窗⼝宽度,这可能会影响诸如媒体查询之类的事情
windowHeight Window.innerHeight渲染元素时使⽤的窗⼝⾼度,这可能会影响诸如媒体查询之类的事情Name Default Description
忽略元素
options有⼀个ignoreElements参数可以⽤来忽略某些元素,从渲染过程中移除,除了设置该参数外,还有⼀种忽略元素的⽅法,就是在需要忽略的元素上增加data-html2canvas-ignore属性。
<div data-html2canvas-ignore>Ignore element</div>
2 基本原理孟庭苇照片
介绍完html2canvas的使⽤,我们先来了解下它的基本原理,然后再分析细节实现。
它的基本原理其实很简单,就是去读取已经渲染好的DOM元素的结构和样式信息,然后基于这些信息去构建截图,呈现在canvas画布中。它⽆法绕过浏览器的内容策略限制,如果要呈现跨域图⽚,需要设置⼀个代理。
3 主流程 html2canvas⽅法
基本原理很简单,但源码⾥⾯其实东西很多,我们⼀步⼀步来,先到⼊⼝,然后慢慢调试,⾛⼀遍⼤致的流程。
寻⼊⼝⽂件
拉取到源码,有很多⽅法可以到⼊⼝⽂件:
⽅法⼀:最简单的⽅法是直接全局搜索html2canvas,这种⽅法效率很低,⽽且要碰运⽓,不推荐
⽅法⼆:在项⽬中引⼊这个库,调⽤它,跑起来,并在该⽅法前⾯打断点进⾏调试,⼀般能精确地到⼊⼝⽂件,推荐
⽅法三:观察下是否有fig.js或者fig.js的构建⼯具的配置⽂件,然后在配置⽂件中到精确的⼊⼝⽂件(⼀般是entry或input之类的属性),推荐
⽅法四:直接扫⼀眼⽬录结构,⼀般⼊⼝⽂件在src/core/packages之类的⽬录下,⽂件名是index或者main,或者是模块的名字,有经验的话可以⽤这个⽅法,起来很快,强烈推荐
⽅法⼀:全局搜索
最简单最容易想到的的⽅法,就是全局搜索关键字html2canvas,因为我们在不了解html2canvas的实现之前,我们接触到的关键字就只有这⼀个。
但是全局搜索运⽓不好的话,很可能搜出来很多结果,在⾥⾯⼊⼝⽂件费时费⼒,⽐如:
42个⽂件285个结果,起来很⿇烦,不推荐。
⽅法⼆:打断点
在调⽤html2canvas的地⽅打⼀个断点。
然后在执⾏到断点处时,点击向下的⼩箭头,进⼊该⽅法。
因为在开发环境,很快我们就能发现⼊⼝⽂件和⼊⼝⽅法在哪⼉,这⾥显⽰的是html2canvas⽂件,实际上这个⽂件是构建之后的⽂件,但是这个⽂件的上下⽂给我们提供了⼊⼝⽅法的信息,这⾥我们发现了renderElement⽅法。
这时我们可以尝试全局搜索这个⽅法,很幸运直接到了
⽅法三:配置⽂件
寻配置⽂件⼀般也要靠经验,⼀般配置⽂件都会带.config后缀常见构建⼯具的配置⽂件:
构建⼯具配置⽂件
fig.js
fig.js
fig.js
Grunt Gruntfile.js
配置⽂件到,⼊⼝⽂件⼀般很容易就到