查阅很多资料后,几乎没有一个能完整解决问题的,都是东平西凑,各种调试才勉强解决生成图片的坑。

因为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的问题,且只生成一张图。多图的暂时为尝试。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐