需求:实现一个快照功能。
快照:要根据需求实现页面长截图(整个页面)或者页面中的某部分进行截图
技术:canvas是底层,其中我们使用了基于canvas的第三方插件
核心原理:html2canvas.js 能够实现在用户浏览器端直接对整个或部分页面进行截屏(包括页面中写的样式)
问题:页面布局是flex布局,页面上下固定,中间自适应的时候,当我们通过document.body获取截到的就只是可视区域的内容,当页面内容有超出时,因为最外层盒子不能滑动,所以会导致截取到的图片不全。但如果单独对中间自适应的内容截取,中间自适应超出的内容也能截取到,这是因为html2canvas在截取时会对设置的样式也生效。也就是说界面是什么样的css,截图得到的就是一样的(相同的输入得到相同的输出)
解决思路:全截屏写两套独立的元素并布局,当截图的是时候显示全截图的元素(可全局滑动),未截图时展示局部滑动的元素。
当全截图时,需要隐藏页面部分不需要截图的元素,
给元素添加 data-html2canvas-ignore=“true”
<div data-html2canvas-ignore class="group_4 flex-col">
</div>
用法: 安装html2canvas
npm install html2canvas //安装
import html2canvas from 'html2canvas'; 使用
const uploadSign = async () => {
data.form.confirmStatus = "MANUAL_SIGN";
Toast("加载中");
const billImageRes = await uploadFile(document.body);
console.log(billImageRes);
const signRes = await uploadFile(document.querySelector("#sign-img"));
console.log(signRes, "signRes图片地址===");
const params = {
id: data.form.id,
billImage: billImageRes.data.file.pic_id,
signatureImage: signRes.data.file.pic_id,
detailUrl: data.form.detailUrl,
};
// console.log(params);
// return;
const res: any = await addFscSignature(params);
if (res.code != "000000") {
data.form.signPictureUrl = "";
data.form.confirmStatus = "UN_SIGN";
vuexStore.commit("setIsUpdate", false);
isScreenShot.value = false;
Toast.fail(res.msg);
} else {
data.form.confirmStatus = "MANUAL_SIGN";
isScreenShot.value = false;
await loadData();
if (router.currentRoute.value.query.pageSource == "H5") {
vuexStore.commit("setIsUpdate", true);
}
}
};
问题:
图片跨域:如果需要截图的地方包含其他域名的图片,那么会出现跨域问题
解决:
1)设置useCORS:true,
2)**把后端的图片转成base64**
```javascript
1:通过调取接口转换
1.1 得到接口结果在页面渲染需赋值:**data:image/png;base64**
```javascript
const res = await convertToBase64({
img: response.data.imageUrl,
// img: 'https://dsl-ds.dslbuy.com/A37164C4830F49D7ACC824B97B346BB7.png', //response.data.imageUrl,
});
console.log(res.data, "原生返回的图片地址===", res);
data.form.signPictureUrl = `data:image/png;base64,${res.data}`;
2:前端转换
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
// e.target.result 即为base64结果
console.log(e.target.result);
};
3)将图片都放在同一个域名下
注意:
1:document获取需要截取的HTML元素,其中注意,通过选择器获取的元素不能重名,需唯一(如#sign-img只能出现一次)
2:当页面中有图片时,需要设置 useCORS: true, //配置允许跨域
uploadFile :得到的二进制图片提交给接口
```javascript
const uploadFile = async (dom) => {
const options = {
backgroundColor: null,
useCORS: true, //配置允许跨域
dpi: 300, // 处理模糊问题
height: dom.scrollHeight + dom.scrollTop + 40,
};
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
const canvas = await html2canvas(dom, options);
const file = canvas.toDataURL("image/png");
console.log(file, "截到的图片=====", canvas);
var formData = new FormData();
let blob = dataURLtoFile(file, "image/jpeg");
let fileOfBlob = new File([blob], new Date() + ".jpg");
formData.append("file", fileOfBlob);
const res = await addFile(formData);
return res;
};
3:同时页面中的图片元素设置**crossorigin=“anonymous”**允许跨域
<img
:src="data.form.signPictureUrl"
alt="sign"
class="sign-img"
crossorigin="anonymous"
/>
4:当全截图的时候,需要分别设置如下两点 scrollTop=0
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
5:截图得到的是base64的图片,但是我们传递给后端的一般是二进制,所以需要进行base64和二进制之间的转换
dataURLtoFile :文件转换
const dataURLtoFile = (dataURI, type) => {
let binary = atob(dataURI.split(",")[1]);
let array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], { type: type });
};
扩展:不同文件之间的转换
https://editor.csdn.net/md/?articleId=134682076