纯前端H5,利用html2canvas,base64转码,生成图片,解决iOS和安卓微信的坑,生成不全,空白,跨域等问题。
查阅很多资料后,几乎没有一个能完整解决问题的,都是东平西凑,各种调试才勉强解决生成图片的坑。因为canvas始终会跨域,一般都是通过设置后端,改的麻烦也不知道行不行,所以就前端自己想办法解决,绕过后端。canvas生成图片有要求,不可以是display:none;我是定位z-index负值,不设置透明度,除非你要生成透明的。先贴下代码:<!-- 遮罩层--商品分享海报 --...
查阅很多资料后,几乎没有一个能完整解决问题的,都是东平西凑,各种调试才勉强解决生成图片的坑。
因为canvas始终会跨域,一般都是通过设置后端,改的麻烦也不知道行不行,所以就前端自己想办法解决,绕过后端。
canvas生成图片有要求,不可以是display:none;我是定位z-index负值,不设置透明度,除非你要生成透明的。
先贴下代码:
<!-- 遮罩层--商品分享海报 -->
<template v-if="showPoster">
<div class="cover-content">
<div>
<div class="cover" @click.stop="showPoster = false"></div>
<div class="content" ref="imageWrapper" id="imageWrapper" :style="{height:testTitle.length >19 ?'9.6rem':'9.34rem'}">
<div class="poster-img">
<!-- <img src="./yaoqinghaoyoubeijing_9_10.31@3x.png" alt=""> -->
<!-- canvas生成图片受跨域限制,利用base64转码方式解决 -->
<img :src="posterimgUrl" alt="">
</div>
<!-- canvas 生成图片不支持webkit多行省略,暴力截取字符串解决 -->
<p class="title">{{testTitle.length >38 ?(testTitle.substring(0,37)+'...') :testTitle.substring(0,38)}}</p>
<ul class="bottom-content">
<li>
<!-- 生成二维码 -->
<div class="qrcode" ref="qrcodeContainer"></div>
</li>
<!-- 竖线 -->
<li></li>
<li>
<p style="color:#e81844;margin-top:0.21rem;font-size:0.3rem;font-weight:600;">¥<span style="font-size:0.46rem;margin-left:0.1rem;">979.00</span></p>
<p style="margin-top:0.3rem;margin-left:0.1rem;color:#666;font-size:0.24px;">识别图中二维码</p>
</li>
</ul>
</div>
<div class="button-shares" :style="{bottom:testTitle.length >19 ?'1.6rem':'1.7rem'}">
<div class="share-poster-img" @click.stop="shareToThirdParty">分享链接</div>
<div class="share-poster-img" @click.stop="saveImg">保存图片</div>
</div>
</div>
<!-- 最终生成海报图 -->
<img v-if="imgUrl" :src="imgUrl" @click="tipSaveImg" width="315" height="467" alt="" style="position:fixed;z-index:99;top:50%;left:50%;transform:translate(-50%,-50%);">
</div>
</template>
此处为了方便,我直接写的内联样式,可无视、
import QRCode from 'qrcodejs2' // 引入qrcode
import html2canvas from "html2canvas" // 生成图片;
import CompassImg from '@/common/js/filerar.js'
data(){
return {
showPoster: false,
imgUrl : '', // 海报生成图
posterimgUrl:'',// 海报图链接base64转码
}
},
watch:{
posterimgUrl(){ // 监听转码后的base64图片,有才生成图
if(this.posterimgUrl){
setTimeout(()=>{
this.createImage();
})
}
}
},
methods:{
// 展示分享海报
toShowPoster() { // 点击这个按钮生成图片,上图html里没展示,随便写哪里都行、
this.handleScroll();
setTimeout(()=>{ // 转码生成之前,先监听滚动,否则出现截图不全甚至图片为空、
this.showPoster = true; // 显示要被生成的海报元素
this.showQRCode(); // 生成二维码 qrcodejs插件
this.getPosterimgUrl(); // 获取海报图的图片链接,并转码
})
},
handleScroll() {
// 获取滚动距顶部的距离,显示
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
if(scrollTop>0){// 监听是否滚动,只要滚动了,每次点击生成的时候就让页面回到顶部,解决因滑动导致的生成图片不全甚至空白、
console.log(scrollTop,'scrollTop');
var c = setTimeout(() => window.scrollTo(0, 0), 16);//滚动至顶部
}else{
console.log('销毁');
clearTimeout(c);
}
},
showQRCode() { // 生成二维码
this.$nextTick(()=>{
var qrcode = new QRCode(this.$refs.qrcodeContainer, {
text: 'https://www.baidu.com,
width: '75',
height: '75',
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
})
})
},
// 后端传入的图片链接src,转码
getPosterimgUrl() {
let pimg = this.product_data.image_banner[0]; //后端获取的图片链接
// let index = pimg.toLowerCase().indexOf('.com') + 4;
// let indexstr = pimg.substr(0,index);
// let newImg = pimg.replace(indexstr,'//file.xxx.com');
// console.log(newImg);
var image = new Image();
// image.crossOrigin = "*"; // 支持跨域图片 这一行会导致iOS微信报安全错误,换下一行的方式写法就好了,安卓没发现问题、
image.setAttribute("crossOrigin",'anonymous'); // 解决iOS微信端报错 securityError...insource啥的、
image.src = pimg + '?v=' + Math.random(); // 处理缓存
image.onload = ()=>{//一定要在onload后去压缩转码,否则可能因图片未加载传入,报错或者undefind之类的
var base64 = CompassImg(image);
this.posterimgUrl= base64 // 将压缩转码后的图片保存,用以生成海报
}
},
// 生成最终海报图
createImage() {
html2canvas(this.$refs.imageWrapper,{
useCORS: true,
backgroundColor: null,
allowTaint: true
}).then((canvas) => {
let dataURL = canvas.toDataURL("image/png");
this.imgUrl = dataURL;
});
},
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll); //离开页面需要移除这个监听的事件
console.log('监听销毁-- this.handleScroll');
},
// compassImg引入的方法 filerar.js文件 base64压缩图片的方法
/* function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataURL = canvas.toDataURL("image/png"); // 可选其他值 image/jpeg
return dataURL;
}
export default getBase64Image
*/
看下效果图:
安卓和iOS都未报错。只打印了销毁。other_err忽略,其他组件的。
看下本地的iOS调试效果。滑动后的:
滑动后,生成正常。按钮是悬浮出来的,如果包含在生成图的元素里,就会按钮也展示了。本地忽略了调试,只在真机调试了位置。
看看生成的图:
无按钮,可以长按保存。可识别二维码。
下面再捋一捋思路。
在无后端帮助解决canvas跨域(非本地图片)的情况下,直接生成的图会显示空白。想了一个办法:
1、那就在生成前,把需要的图片src进行base64转码;(这里很多坑,iOS,安卓都有区别。图二js里解释了)
2、转码成功后,可以正常生成图片,但是发现新的问题,只要滑动了。就会截取少了滑动的部分。我选择暴力解决,转码生成前就去监听scroll事件,如果滚动了就让回到顶部,再生成。这就需要一个异步处理了。关闭页面,销毁监听。
本文是查阅了很多百度资料,综合解决了自己的H5微信ios,android的问题,且只生成一张图。多图的暂时为尝试。
更多推荐
所有评论(0)