最近vue2项目里做一个生成海报的功能,需要用到html2canvas。
html2canvas是纯js对浏览器端进行截图,允许直接在浏览器上拍摄网页或某一部分进行截图。但由于它的截图是基于DOM
的,因此可能不会100%精确到真实的表示,因为它不会生成实际的屏幕截图,而是基于页面上可用的信息构建屏幕截图。
附上官方网址:html2canvas - Screenshots with JavaScript
官方网址里介绍比较简单,是通过获取DOM元素来进行截图,我这里是通过ref属性,所以实际使用过程中要根据情况选用,这里基于我项目中的实例做介绍。
1、安装
npm install html2canvas --save
2、在要使用的页面中引入
import html2canvas from "html2canvas";
3、使用
使用上分两部分来说,第一部分是基于<img>标签截取图片,第二部分是基于<div>标签截取全部内容。
(1)基于<img>标签截取
这里涉及到一个问题,截取<img>标签内容是通过自定义属性(这里指 :data-imgurl)实现的,但<img>标签绑定自定义属性的同时,动态绑定src属性,控制台会报错,目前不清楚具体因为什么,但解决方式是页面显示部分和实际截取区域分开,然后通过定位把实际截取区域隐藏,这部分要结合css 代码来理解。
直接上完整代码
<template>
<div class="infoWap">
<!-- 页面显示区域 -->
<div class="loadView">
<div class="course">
<img :src="coverImg" alt="" >
</div>
</div>
<div class="operateView">
<van-button type="info" @click="saveImage" class="saveBtn">保存</van-button>
</div>
<!-- 实际截图区域,在页面中隐藏 -->
<div class="outImg" ref="imageDown">
<img src="" alt="" :data-imgurl="coverImg" ref="coverImgRef" >
</div>
</div>
</template>
<script>
import html2canvas from "html2canvas";
import { Button, Toast } from 'vant';
export default {
data() {
return {
coverImg:'', //从接口获取到的图片路径
}
},
// 保存海报
saveImage(){
// 增加loading提示
let saveLoading = Toast.loading({
duration: 0,
message: '海报生成中...',
forbidClick: true,
});
let url = that.$refs.coverImgRef.dataset.imgurl; //获取data-imgurl属性值
let canvas = document.createElement('canvas'); //创建canvas元素
let ctx = canvas.getContext('2d');
let img = new Image();
img.crossOrigin = 'Anonymous'; // 重点!设置image对象可跨域请求
img.src = url + "?timeStamp=" + new Date().getTime(); //解决缓存引起访问失败需要添加时间戳
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg');
// console.log(dataURL);
that.$refs.coverImgRef.src = dataURL;
html2canvas(that.$refs.coverImgRef, {
backgroundColor: null, //设置背景为透明色
useCORS: true, //支持图片跨域
scale: 2, // 处理模糊问题
dpi: 300, // 处理模糊问题
}).then((canvas) => {
console.log(canvas)
// 把生成的base64位图片上传到服务器,生成在线图片地址
let url = canvas.toDataURL("image/png");
that.imgUrl = url;
//将图片下载到本地
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window
});// 创建一个单击事件
a.download = "海报.png"; // 设置图片名称
a.href = that.imgUrl; // 将生成的URL设置为a.href属性
a.click();
// console.log(a)
a.setAttribute("target", "_blank");
a.dispatchEvent(event); // 触发a的单击事件
}).finally(()=>{
saveLoading.clear(); //清除loading
})
}
},
}
</script>
<style lang="scss" scoped>
.infoWap{
height: 100vh;
width: 100vw;
overflow: hidden;
position: relative;
.outImg{
position: absolute; //子元素增加定位,在页面中隐藏
left: 100%;
top: 100%;
height: 100vh;
width: 100vw;
padding: 0.2rem 0.5rem 1.7rem 0.5rem;
box-sizing: border-box;
img{
width: 100%;
height: 100%;
}
}
.loadView{
height: 100vh;
width: 100vw;
padding: 0.2rem 0.5rem 1.7rem 0.5rem;
box-sizing: border-box;
.course{
width: 100%;
height: 100%;
img{
width: 100%;
height: 100%;
}
}
}
.operateView{
width: 100vw;
height: 1.5rem;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.saveBtn{
flex: 1;
}
}
}
</style>
(2)截取<div>标签内容
<template>
<div>
<!-- 头部自定义菜单栏 -->
<div class="topView">
<p class="goBack" @click="goBack">返回</p>
<p class="saveBtn" @click="handelSaves">保存</p>
</div>
<!-- 截取内容 -->
<div>
<div class="canvasView">
<div class="canvasImg" ref="canvasImg">
<img :src="backgroundPicture" alt="" class="backImg">
<!-- 用户名称 -->
<div class="nameView">{{pageData.title ? pageData.title : '手动创建文字'}}</div>
<!-- 用户图片 -->
<div class="afterCropper">
<img :src="pageData.uploadPicImage ? pageData.uploadPicImage : userImg" alt="" />
</div>
<!-- 用户二维码 -->
<img :src="pageData.qrCode ? pageData.qrCode : defaultQr" class="userQrImg" >
</div>
</div>
</div>
</div>
</template>
<script>
import html2canvas from "html2canvas";
export default {
data() {
return {
pageData:{}, //所需数据
}
},
methods:{
let that = this;
let imgHeight = that.$refs.canvasImg.offsetHeight; // 获取DOM高度
let imgWidth = that.$refs.canvasImg.offsetWidth; // 获取DOM宽度
let saveLoading = Toast.loading({
message: '海报生成中...',
forbidClick: true,
});
// 截取海报
html2canvas(that.$refs.canvasImg, {
useCORS: true, //允许跨域
backgroundColor: '#ececec', //画布背景色,设置null为透明
width: imgWidth, //画布宽
height: imgHeight, //画布高
scale: 2, // 处理模糊问题
dpi: 300, // 处理模糊问题
}).then((canvas) => {
// 返回一个 canvas 对象,在dom中渲染 canvas 对象
// 转化成 dataurL
let url = canvas.toDataURL("image/png");
that.imgUrl = url;
//调用下载方法
let a = document.createElement("a"); //创建一个a标签
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = "海报"; // 设置图片名称
a.href = that.imgUrl; //指定下载文件名称
a.dispatchEvent(event); // 触发a的单击事件
// 这里可以获得截取到的base64格式的图片-url,可进行后续操作,比如传入接口等
});
}
}
</script>
<style lang="scss" scoped>
.editView{
width: 100vw;
height: 100vh;
background-color: #333;
.topView{
width: 100%;
height: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
font-size: 0.3rem;
padding: 0 0.5rem;
box-sizing: border-box;
.goBack{
width: 20%;
height: 1rem;
text-align: center;
line-height: 1rem;
}
.saveBtn{
width: 20%;
height: 1rem;
text-align: center;
line-height: 1rem;
}
}
.canvasView{
width: 100%;
height: calc(100vh - 2rem);
padding: 0.5rem 1rem;
box-sizing: border-box;
.canvasImg{
width: 100%;
height: 100%;
// background: url('../../../assets/img/canvasBack.jpeg') no-repeat no-repeat center;
background-repeat: no-repeat;
background-size: 100% 100%;
position: relative;
.backImg{
width: 100%;
height: 100%;
}
.nameView{
width: 45%;
font-size: 0.38rem;
color: #fff;
position: absolute;
top: 8%;
right: 3%;
}
.afterCropper{
width: 86%;
height: 29%;
position: absolute;
top: 26%;
left: 6%;
-webkit-transform: rotate(-4deg);
transform: rotate(-4deg);
img{
width: 100%;
height: 100%;
}
}
.userImg{
width: 82%;
height: 42%;
position: absolute;
top: 38%;
left: 10%;
}
.userQrImg{
width: 1rem;
height: 1rem;
position: absolute;
bottom: 5%;
right: 3%;
}
}
}
}
</style>
(3)需要注意两点,一是截取后的图片是base64格式,如果需要转换其他形式,可以参考这些方法。
<1>图片转为base64格式
// 图片转为base64格式
getBase64Image(img) {
let canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
let ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
let dataURL = canvas.toDataURL("image/" + ext);
return dataURL;
},
使用时:
if (imgUrl != "") { // 判断一下要传入的图片是否存在
let that = this;
that.imgUrl = imgUrl;
let image = new Image();
image.src = imgUrl + "?v=" + Math.random(); // 处理缓存
image.crossOrigin = "*"; // 支持跨域图片
image.onload = function() {
let base64 = that.getBase64Image(image); //调用函数并将其转为base64图片
// console.log(base64) // 可以打印一下验证
that.backPicture=base64 // 赋值后可在页面进行使用
};
}
<2>base64图片转文件流
// base64图片转文件流
base64toFile(dataurl,filename){
let arr = dataurl.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let suffix = mime.split('/')[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], `${filename}.${suffix}`, {
type: mime
});
},
使用时:
// 上传图片文件
uploadPoster(photo){
let imgFile = this.base64toFile(photo);
// 进行接口请求等操作
// ...
}
还有一点需要注意的是,如果使用background-image属性动态设置背景图,截取后生成的图片会很模糊,所以使用<img>标签设置背景:
以上就是本次使用html2canvas的内容,欢迎大家点赞评论。