• 小程序生成分享海报图片并保存相册


    前言

    最近开发的小程序都有分享需求,功能大体为点击分享按钮,或主动生成海报后,用户操作保存对应海报为图片实现分享。以下是具体实现。

    最终生成效果如图:
    在这里插入图片描述

    一、普通二维码生成

    此处主要是生成工具库来生成普通二维码,如果要生成小程序码,只能通过后台接口调用开放API实现,且需要小程序已上线发布才能通过微信扫一扫进入小程序(废话不多说了。。。。)

    • 工具库:weapp.qrcode.min.js

    template

    <template>
    	<view class="page">
    		<canvas
              id="canvas"
              style="width: 160rpx; height: 160rpx"
              canvas-id="canvas"
            >canvas>
    	view>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    script

    // 调用很简单
    const drawQrcode = require("@/lib/weapp.qrcode.min.js)
    export default {
    	data(){return {}};
    	onLoad(){
    		this.drawCode();
    	}
    	methods:{
    		drawCode(){
    			drawQrcode({
    				text: `二维码内容`,
    				canvasId: "canvas",
    				width: 80,
    				height: 80
    			})
    			console.log("二维码生成")
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二、生成海报图片并保存

    生成海报分为两步
    一是海报预览弹窗(这个是小程序内页弹窗所以直接代码编写就好)
    二是通过painter将元素生成为图片保存到本地。以下代码只描述重点部分,全部代码请查看源码文件。
    这里用到了painter这个组件库,这是一个通过配置json就直接生成图片的工具库,开源地址

    1、引入依赖组件

    这里引用了painter组件来生成(懒人不想造轮子- _ -)。因为是微信原生编写,所以放在根目录下的wxcomponents中

    目录如下:

    |__ wxcomponents
    	|__ painter
    		|__ painter.wxml
    		|__ painter.wxss
    		|__painter.json
    		|__painter.js
    		|__ ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    page.json中引入微信组件

    {
    	"globalStyle":{
    		"usingComponents": {
    			"painter": "/wxcomponents/painter/painter"
    		 }
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、生成海报图片

    这里新建了两个文件,一个share.vue用于在小程序中直接展示海报的样式,一个share.js是配置painter海报的数据源

    • share.vue
    <template>
      <view class="share" v-if="visible">
        <view class="share-content">
          <view class="share-chart-wrap">
            <image
              class="share-chart"
              @longpress="saveImgNow"
              src="http://qiniu.kingdou.fun/kingdou1.jpeg"
              mode="widthFix"
            />
            <view class="share-title">这是每报标题view>
          view>
          <view class="share-card">
            <view class="content-block">
              <view class="content-row">
                <view class="content-label">海报时间view>
                <view class="content-value">{{ data.time }}view>
              view>
              <view class="content-row">
                <view class="content-label">描述view>
                <view class="content-value">{{ data.introduce }}view>
              view>
              <view class="content-row">
                <view class="content-label">比赛说明view>
                <view class="content-value">限定时间内根据动作次数记分view>
              view>
            view>
            <view class="qr-block">
              <view class="qr-tips">
                <view class="tips-title">长按图片进行保存或者转发view>
                <view class="tips-content"
                  >扫描二维码即可参赛~<br />快去分享吧~
                view>
              view>
              <slot name="qrcode" @longpress="init">slot>
            view>
          view>
        view>
        <uni-icons
          class="close-btn"
          size="50"
          type="close"
          color="#fff"
          @click="close"
        />
        <painter
          v-show="isSave"
          style="position: absolute; top: 79rpx; left: 60rpx"
          :palette="template"
          @imgOK="onImgOK"
          @imgErr="onImgErr"
        />
      view>
    template>
    
    <script>
    	import Card from "./share";
    
    	export default {
    		props: {
    			visible: {
    				type: Boolean,
    				default: false,
    			},
    			data: {
    				type: Object,
    				default: () => {
    					return {
    						time: "",
    						introduce: "",
    					};
    				},
    			},
    		},
    		data() {
    			return {
    				imagePath: "",
    				template: "",
    			};
    		},
    		methods: {
    			saveImgNow() {
    				let data = { ...this.data};
    				this.template = new Card().palette(data);
    			},
    			saveImage() {
    				if (this.imagePath && typeof this.imagePath === "string") {
    					// 图片保存到本地
    					wx.saveImageToPhotosAlbum({
    						filePath: this.imagePath,
    					});
    					// 关闭分享弹窗
    					setTimeout(() => {
    						this.$emit("update:visible", false)
    					}, 500)
    				}
    			},
    			close() {
    				this.$emit("close");
    			},
    			onImgOK(e) {
    				this.imagePath = e.detail.path;
    				this.saveImage(this.imagePath);
    			},
    			onImgErr() {
    				console.log("保存图片失败");
    			},
    		},
    	};
    script>
    <style lang="scss" scoped>
    样式内容省略,详见源码。。。
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • share.js (内容太多,这里就只截部分作为参考,全部内容请参考文末的源码包)PS:这个文件通过工具生成并不需要自己编写
    export default class LastMayday {
        palette(data) { // 传入动态数据源  
          return {
            width: "320px",
            height: "430px",
            background: "#f1f1f1",
            views: [
              {
                type: "text",
                text: "海报时间",
                css: {
                  color: "#373737",
                  background: "rgba(0,0,0,0)",
                  width: "60px",
                  height: "15.819999999999999px",
                  top: "202px",
                  left: "40px",
                  // 。。。。省略
                },
              },
                {
                type: "text",
                text: data.time, //这里是动态数据
                css: {
                  color: "#0061D4",
                  background: "rgba(0,0,0,0)",
                  width: "181px",
                  height: "15.819999999999999px",
                  top: "202px",
               		// 。。。。省略
                },
              },
              // 。。。。。
              }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    2.1 配置painter海报json

    这里即是对上面的share.js来历进行说明。要生成图片,得有生成图片的规则,也就是painter的绘制数据源。这里也是通过第三方网站来可视化生成的,通过在这个网站中先绘制好海报的样式后,再一键生成json文件,最后放进代码中。

    2.2 引入数据构造函数并在适当时间触发生成海报
    • 在本文示例中是通过长按图片来触发,当然也可以是用户直接点击按钮来触发
    import Card from './share.js'
    export default {
    	// 。。。。省略。。。
    	methods: {
    	// 这里假设用户长按图片,触发此方法。即上面share.vue中, @longpress="saveImgNow"
    	saveImgNow() {
    		let data = { ...this.data};
    		this.template = new Card().palette(data);
    	},
    	// 生成图片事件监听(在调用new Card()后会自动触发
    	// 图片生成成功时
    	onImgOK(e) {
    		this.imagePath = e.detail.path;
    		this.saveImage(this.imagePath);
    	},
    	// 图片生成失败时
    	onImgErr() {
    		console.log("保存图片失败");
    	},
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2.3 弹窗组件中直接使用painter组件
     <painter style="position: absolute; top: -799999rpx; left: -999960rpx" :palette="template" @imgOK="onImgOK"
    			@imgErr="onImgErr" />
    
    • 1
    • 2
    • 这里style中的内容是为了在视觉上隐藏海报(本质上是通过canvas再生成海报,所以需要此元素显示后再在canvas上绘制为图片)

    三、源码

    地址参见:https://gitee.com/sophie-code-box/share-poster

  • 相关阅读:
    039:vue中数字货币化快速显示
    【总结】有三AI所有原创GAN相关的技术文章汇总(2022年8月)
    idea创建包时无法分层
    【C语言刷LeetCode】2295. 替换数组中的元素(M)
    八、Docker容器的数据管理
    开发阶段部署
    labview技术交流-判断两个数组的元素是否完全相同
    518晚会聚会抽奖软件,可用作游戏随机抽签选人
    STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计
    精准营销!用机器学习完成客户分群!
  • 原文地址:https://blog.csdn.net/Sophie_U/article/details/127675368