目录
我对canvas的理解:是一个画布,可以通过一些指令在上面画画
在一个空白的canvas画布上新增文案或图片:
要一点一点的画,一个一个的加上去,内容多一些就麻烦
const canvas = document.createElement("canvas"); // 生成一个canvas节点
const ctx = canvas.getContext("2d");
canvas.width = 200; // 设置画布的宽
canvas.height = 100; // 设置画布的高
// 将文案放到画布上
ctx.textBaseline = "top"; // 文案的位置格式,可以去百度上搜索一下,看不同格式的区别
ctx.font = window.getComputedStyle(window.document.getElementById('root')).font // 获取节点的字体(修改画布的文案字体)
ctx.fillText('文案', 10, 20); // 将 ‘文案’ 放到画布坐标 x = 10, y = 20 的位置
// 将图片放到画布上(知道图片url)
const img = new Image();
img.src = 'xxx'; // 设置图片的url
img.crossOrigin = "anonymous"; // 防止图片跨域,获取不到
img.onload = () => {
// 在画布坐标 x = 10, y = 20 的位置,放置图片
// 图片的宽为 30,高为 40
ctx.drawImage(img, 10, 20, 30, 40);
// TODO:代码执行到这里图片才放到画布上
}
// 生成图片url,第一个参数按需修改,例如:'image/png'
const base64image = canvas.toDataURL('image/jpeg', 1);
// 如需下载,可以通过以下代码触发浏览器下载
const a = document.createElement("a");
a.href = canvas.toDataURL("image/png");
a.download = 'img';
a.click();
使用工具包 html2canvas
安装
- 可以在按照官网的方式下载
- 也可以直接加到html里面:
<script src='https://html2canvas.hertzen.com/dist/html2canvas.min.js'></script>
一般的使用
async function () {
const domCanvas = await html2canvas(document.body, { // 复制body展示的内容
useCORS: true, // 如果有图片,可以通过这个支持跨域
});
const canvas = document.createElement('canvas');
canvas.width = domCanvas.width;
canvas.height = domCanvas.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(domCanvas, 0, 0, canvas.width, canvas.height);
const base64image = scaledCanvas.toDataURL('image/jpeg', 1);
}
修改dom样式之后,再将内容放到canvas上(前提:不能修改浏览器展示的内容)
修改样式的方法(这个只作参考)
在html上新增一个参数,通过这个参数控制页面上的渲染以及样式
修改html上的参数:
document.documentElement.setAttribute('abc-aaa', 'a');
例如less文件中:
// 参数名是abc-aaa,值可以为a
html[abc-aaa='a'] .classname {
// 样式
}
如果内容中没有background-image等样式需要修改
html2canvas(document.body, {
useCORS: true,
onclone: (cb, e) => {
// 直接在这个里面修改对应的内容就行,cb相当于document,e是传入的节点(当前是document.body)
},
});
如果内容中有background-image等样式需要修改
测试方案1(无用):
html2canvas(document.body, {
useCORS: true,
onclone: (cb, e) => {
// 这里修改克隆的dom不方便,像下面这样直接增加样式也不会生效
// TODO:下面代码不会影响canvas的内容样式
const style = cb.createElement('style');
cb.body.appendChild(style);
style.sheet.addRule('.aaa', 'background-image: linear-gradient(to right, rgba(255, 255, 255, 0) 70%, #fff) !important');
},
});
测试方案2(无用):
const body = document.body.cloneNode(true);
xxx // 这里修改clone的body内容
html2canvas(body, { // 这个里面不知道触发了什么,直接跳出了
useCORS: true,
});
测试方案3(有用,看情况使用):
这样可以将clone的dom进过 html2canvas 变成 canvas,但是页面上会多出一个dom
// 下面两行模拟一下克隆dom,然后挂载到真实dom上(因为写的是body和html,所以不生效很正常)
const body = document.body.cloneNode(true);
document.documentElement.appendChild(body);
xxx // 这里修改clone的body内容
html2canvas(body, {
useCORS: true,
});
测试方案4(有用,不推荐):
<body>
<div id="root"></div>
<!-- 新增这个mark节点,打个标记 -->
<div id="mark"></div>
</body>
// 在外面就修改样式那些,
html2canvas(document.body, {
useCORS: true,
ignoreElements: e => {
if (e.id === 'mark') {
// 将样式修改回来
}
return false;
};
});
坑1: html2canvas转化textarea标签
现象: textarea内容全部在一行展示,不会换行展示
解决方法: 可以在textarea标签旁边新增一个dom(平时是隐藏的),这个dom里面的内容和textarea一样
通过上面的方法修改样式,在打印的时候把textarea隐藏,新增的那个dom展示
坑2: html2canvas转化的dom有背景图片
现象: safari浏览器上,toDataURL会直接报错(The operation is insecure )
解决方法: 可以用我上面修改样式的方法
注意!visibility 隐藏是会保留原本高度的,具体一些样式细节需要自己改动一下
- 将原本的dom节点的样式加上一个
// 打印时新增的样式
visibility: hidden; // 隐藏dom,这样toDataURL可以正常运行
- 新增一个img,src就是背景图的url,默认样式就是隐藏的
// img默认样式加上
visibility: hidden; // 隐藏img标签
// img打印时样式,这里的样式要调整一下,和预期打印的样式一样
visibility: visible; // 展示img标签