公司需求:宣传海报从后台获取,二维码地址也从后台获得,然后生成一个海报,海报上固定位置放二维码,长按图片可以保存在本地相册(其实前面的需求是点击按钮,下载海报图到本地相册,然后h5下载的实现原理是生成一个a标签链接,然后下载,在电脑模拟器可以下载,在微信浏览器一点反应没有,所以退一步,长按保存),下面是使用版本,UI插件用的是vant(有赞)
vue:“^2.6.11”,
“html2canvas”: “1.4.1”,
“vant”: “^2.8.1”,
“vue_qrcodes”: “^1.1.3”
从后端获取海报图,获取二维码链接,然后将二维码定位到图片固定位置,最后通过html2canvas生成canvas,然后通过canvas.toDataURL(“image/png”)生成
从第三张图就可以看到长按保存的就是带有二维码的海报图了
实现的原理就是:先把二维码定位到海报图上,然后通过html2canvas生成带二维码的海报,最后用这个图片覆盖在imageWrapper1元素上,才能下载到带二维码的海报图,这也是为什么要等待框显示正在生成海报图。
<template> <!--子组件-->
<div class="posterpopup">
<van-popup v-model="popupVisible" @closed="closePopup">
<div id="imageWrapper1">
<img
class="posterpopup-img"
:src="popupObj.posterurl || popupObj.photourl"
/>
<div class="qrcode1" ref="qrcode" id="imageWrapper">
<qrcode
:url="qrUrl"
colorDark="#000"
colorLight="#fff"
:wid="wid"
:hei="wid"
:imgwid="imgwid"
:imghei="imgwid"
></qrcode>
</div>
</div>
<div class="posterpopup-img1" v-if="posterUrl">
<img :src="posterUrl" id="posterUrl" />
</div>
<div class="posterpopup-wrap">
<img src="@/assets/image/download.png" alt="" />
<div class="wrap-text">长按保存图片</div>
</div>
</van-popup>
</div>
</template>
<script>
import qrcode from "vue_qrcodes";
import html2canvas from "html2canvas";
export default {
name: "PosterPopup",
props: {
popupVisible: false,
popupObj: {
type: Object,
default: {},
},
qrUrl: "",
},
components: {
qrcode,
},
data() {
return {
imgwid: 30, // 二维码logo宽度
wid: 80, // 二维码宽度
wrapWid: 80, // 外边框宽度
posterUrl: "",
controllShow: true,
};
},
methods: {
closePopup() {
this.posterUrl = ''
this.$emit("closePopup");
},
toSaveImage() {
// 保存图片
this.$nextTick(async () => {
var imageWrapper = document.getElementById("imageWrapper1");
try {
let canvas = await html2canvas(imageWrapper, {
height: imageWrapper.offsetHeight,
width: imageWrapper.offsetWidth,
backgroundColor: null,
useCORS: true,
allowTaint: true,
scrollX: 0,
scrollY: 0,
dpi: window.devicePixelRatio * 2,
// dpi: 300
});
this.controllShow = false;
this.posterUrl = canvas.toDataURL("image/png");
this.$Toast.clear();
} catch (err) {}
});
},
dataURLToBlob(dataurl) {
let arr = dataurl.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
},
watch: {
popupVisible(newVal, oldVal) {
if (newVal) {
this.$Toast.loading({
message: "海报生成中,请稍等",
duration: 0,
className: "zIndex",
});
this.$nextTick(() => {
this.toSaveImage();
});
} else {
this.controllShow = true;
this.$Toast.clear();
}
},
},
};
</script>
<style lang="scss" scoped>
.posterpopup {
.van-popup {
background-color: transparent;
overflow-y: hidden;
width: 568px;
height: 90vh;
}
#imageWrapper1 {
position: absolute;
min-width: 568px;
min-height: 990px;
}
.posterpopup-img {
width: 568px;
height: 100%;
}
.posterpopup-img1 {
width: 568px;
height: 990px;
& img {
width: 100%;
height: 13.2rem;
}
}
.posterpopup-wrap {
position: absolute;
width: 302px;
height: 70px;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
// margin-top: 100px;
margin: 39px auto 0;
& > img {
width: 100%;
height: 100%;
}
.wrap-text {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 30px;
font-size: 30px;
color: #fff;
}
}
#imageWrapper {
position: absolute;
right: 30px;
bottom: 35px;
}
#posterUrl {
position: absolute;
z-index: 2002;
top: 0;
left: 0;
right: 0;
bottom: 90px;
margin: 0 auto;
width: 568px;
}
}
</style>
<!---->
<posterPopup :popupVisible="popupVisible" :popupObj="popupObj" @closePopup="closePopup" :qrUrl="qrUrl"></posterPopup>
1.如果你把海报放到云上(腾讯云,阿里云,七牛云),就是放在CDN上,那么云一定要设置以下的头文件,如果你不设置这个头文件,就有跨域问题,你就一直会生成不成功,实用html2canvas的话只能生成一个空白背景的二维码,这个搞了好久,采用了放在服务器本地,但是服务器本地图片下载又慢,影响体验,搞了几天,才知道一定要设置!!!
1.如果你把海报放到云上(腾讯云,阿里云,七牛云),就是放在CDN上,那么云一定要设置以下的头文件,如果你不设置这个头文件,就有跨域问题,你就一直会生成不成功,实用html2canvas的话只能生成一个空白背景的二维码,这个搞了好久,采用了放在服务器本地,但是服务器本地图片下载又慢,影响体验,搞了几天,才知道一定要设置!!!