在前端生成H5二维码海报

发布时间 2023-06-08 14:35:39作者: jsper

海报图片生成前后端都能实现,个人喜欢在前端生成,主要是前端可以用html+css去实现海报样式,便于调试,对于熟悉前端代码的小伙伴来说再好不过。

以下是在vue项目中的实现,非vue前端同理。

思路及步骤:

1. 用html实现海报效果

制作海报模板图,用js二维码库生成二维码,用CSS的绝对定位实现二维码处于模板图上一层

2. 将html转canvas

用到第三方库html2canvas,npm install html2canvas

3. 将canvas转图片

用到第三方库canvas2image,这个库有点坑,它的源代码并没有实现模块化,然而却提交到了npmjs.com官网!!!无法直接引用其库,我是直接复制代码到项目中使用。

 

html部分

        <el-button type="primary" @click="toShare()" size="small" icon="el-icon-share">生成海报</el-button>

    <!-- 海报生成html模板,为了不让海报显示在页面上,使用绝对定位,且让其漂移到页面外很远的地方 -->
    <div id="posterHtml" class="posterHtml" style="width:390px;height:693px;position:absolute;top:-10000px;left:-10000px;">
      <img
        :src="'https://oss-exam.chanjet.com/ckt_html/poster_template/ec_poster.jpg'"
        crossorigin="anonymous"
        style="width:inherit;height:inherit;position:absolute;z-index: 10;"
      >
      <div style="width:inherit;height:inherit;position:absolute;z-index: 20;display: flex;flex-direction:column;justify-content: flex-start;align-items: center;">
        <div style="font-size:18px;position:absolute;top:30px;width:100%;text-align: left;color:#FFFFCC;text-shadow: 0 8px 10px #FFFFCC;">
          <div style="margin-left: 20px;font-family: 'Arial Black';">我们是【{{teamName}}】团队</div>
          <div style="margin-left: 20px;">正在参加“XX杯”XXXXXX大赛</div>
          <div style="margin-left: 20px;">请为我们的作品投一票吧~</div>
        </div>
        <!-- 二维码 -->
        <img id="posterQRCode" crossorigin="anonymous" style="width:200px;height:200px;position:absolute;top:420px;" />
      </div>
    </div>

    <!-- 分享海报生成后的图片弹窗 -->
    <el-dialog width="350px"   title="作品分享海报" v-if="posterVisible" :visible.sync="posterVisible" append-to-body>
      <div style="margin-top:-30px;display: flex;flex-direction:column;justify-content:center;align-items: center;">
        <div id="myPosterContainer" style="width:100%;display: flex;justify-content: center;align-items: center;"></div>
        <div style="line-height: 30px;">长按图片保存或转发</div>
      </div>
    </el-dialog>

 

js部分

method: {
    toShare() {
      const text = this.getHost() + '/#/2023ec/videoVote?videoInfoId=' + this.videoInfoId
      // 生成二维码
      QRCode.toDataURL(text, {
        width: 200,
        height: 200,
        src: ''
      }).then(url => {
        // <div style="margin:20px 0 20px 0"><img id="qrcode" :src="shortVideoQRCodeURL"/></div>
        document.querySelector('#posterQRCode').src = url
        this.createPoster()
        this.posterVisible = true
      }).catch(err => {
        console.error(err)
      })
    },
    createPoster() {
      // 生成海报
      const vm = this;
      const domObj = document.getElementById('posterHtml');
      var width = parseInt(domObj.style.width);
      var height = parseInt(domObj.style.height);
      var canvas = document.createElement('canvas');
      var scale = 1;
      canvas.width = width * scale;
      canvas.height = height * scale;
      canvas.getContext('2d').scale(scale, scale);
      var opts = {
        scale: scale,
        canvas: canvas,
        width: width,
        height: height,
        useCORS: true,
        allowTaint: false,
        logging: false,
        letterRendering: true
      };
      console.info('准备开始html2canvas')
      html2canvas(domObj, opts).then(function(canvas) {
        var context = canvas.getContext('2d');

        // 重要 关闭抗锯齿
        context.mozImageSmoothingEnabled = false;
        context.webkitImageSmoothingEnabled = false;
        context.msImageSmoothingEnabled = false;
        context.imageSmoothingEnabled = false;
        console.info('准备开始Canvas2Image')
        console.info('canvas2image:', Canvas2Image)
        var img = Canvas2Image.convertToImage(
          canvas,
          canvas.width,
          canvas.height
        );
        vm.postshow = false;
        vm.postcode = false;
        // img.style.width = canvas.width / 2 + 'px';
        img.style.width = '330px';
        // img.style.height = canvas.height / 2 + 'px';
        document.getElementById('myPosterContainer').appendChild(img);
      });
    },
}