uniapp: vue+h5,html2cavas绘制推广海报

429 阅读2分钟

微信公众号生成带参数的二维码developers.weixin.qq.com/doc/offiacc…
在h5+vue中使用html2canvas生成海报时,直接访问mp.weixin.qq.com/cgi-bin/sho… 出现跨域问题

1.设置useCORS: true,crossorigin="anonymous"

这篇文章中分析得比较详细 www.jianshu.com/p/22bd5b98e…

其中,总结了跨域解决方式

image.png

通过查看微信公众号二维码接口响应头,没有Access-Control-Allow-Origin

image.png

2.调用后端接口,返回图片数据

既然前端访问会跨域,那我从后端获取图片数据,再返回给前端。

后端接口

@GetMapping("/image")
    public ResponseEntity<byte[]> getImage() throws IOException {
        String wxQRCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=XXX";

        RestTemplate restTemplate = new RestTemplate();
        byte[] imageBytes = restTemplate.getForObject(wxQRCodeUrl, byte[].class);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG); // 设置图片类型,可根据实际情况修改

        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
    }

前端获取图片

getImage() {
      const apiUrl = 'http://localhost:80/XXX/image'; // 与后端接口的URL保持一致

      axios.get(apiUrl, { responseType: 'arraybuffer' })
        .then(response => {
          const imageBlob = new Blob([response.data], { type: response.headers['content-type'] });
          // 使用wxQRCodeUrl保存图片地址,记得再前面定义
          this.wxQRCodeUrl = URL.createObjectURL(imageBlob);
        })
        .catch(error => {
          console.error(error);
        });
    }

3.html2cavas

使用tn-popup实现弹窗效果,当showQrcode为true时弹窗,其它组件应该有自己的弹窗方法;第一张图片是海报背景图,第二张图片是二维码图,当然可以添加text文字等,通过class的css可以调整图片和文字的位置,createPoster方法会让以上的排版最终形成一张完整的海报图片,也就是第三个image。

<tn-popup v-model="showQrcode" mode="center">
    <view class="canvas-wrap">
        <view class="canvas-content-wrap mb20" id="poster" v-if="!imageData">
            <image :src="originalPosterUrl" class="original-poster" mode="widthFix" crossorigin="anonymous"></image>
            <image :src="qrImageUrl" class="qr-image" crossorigin="anonymous"></image>
        </view>
        <image :src="postImageData" mode="widthFix" v-else></image>
        <button type="primary" @click="createPoster" class="mb20">生成海报</button>
    </view>
</tn-popup>

createPoster方法
npm install html2canvas

createPoster() {
    uni.showLoading({
        title: '正在生成海报'
    })
    let dom = document.querySelector('#poster')
    html2canvas(dom, {
        width: dom.clientWidth, //dom 原始宽度
        height: dom.clientHeight,
        scrollY: 0,
        scrollX: 0,
        useCORS: true
    }).then((canvas) => {
            uni.hideLoading()
            //成功后调用返回canvas.toDataURL返回图片的postImageData
            this.postImageData = canvas.toDataURL('image/png', 1)
    })
},

本文CSS

	.canvas-wrap {
		padding: 40rpx;
		text-align: center;

		.canvas-content-wrap {
			background: rgb(224, 187, 63);
			display: flex;
			flex-direction: column;
			align-items: center;
			color: #ffffff;
			padding: 20rpx;
			z-index: -1;

			.original-poster {
				height: 200rpx;
				margin-bottom: 40rpx;
				z-index: 1;

			}

			.qr-image {
				position: absolute;
				top: 60%;
				/* 调整第二张图片的垂直位置 */
				left: 60%;
				/* 调整第二张图片的水平位置 */
				width: 100px;
				/* 调整第二张图片的宽度 */
				height: 100px;
				z-index: 99;
			}

			.poster-title {
				font-size: 32rpx;
				margin-bottom: 40rpx;
			}
		}
	}

最终展示
image.png

4.补充

(1)后端也可以返回图片的byte[]数据

this.imageUrl = 'data:image/jpeg;base64,' + response.data.data;

(2)生成海报后,图片清晰度下降

将海报图和二维码的image换成img,清晰度提高不少