• uniapp生成自定义(分享)图片并保存到相册


    需求描述

    在这里插入图片描述
    在一个页面中底部有个保存图片的功能,点击能够保存一张生成的自定义表格图片。
    第一眼见到这个需求 自己会出现了两个问题

    1. 如何去处理图片中的自定义内容以及样式
    2. 如何将自定义内容转化成图片
      至于保存图片,uniapp有对应的api去实现uni.saveImageToPhotosAlbum,不做赘述

    实现效果展示

    请添加图片描述
    下面就是生成的图片在这里插入图片描述

    实现步骤

    大致划分成以下几个步骤
    1、需要在目标页面画出图片内容的html代码,并置于于屏幕可视区域外形成隐藏的效果(不是display:none隐藏元素
    2、需要将html转成canvas的形式,再通过toDataURL方法转成base64图片形式
    3、将base64转换成临时图片路径,即可展示出,并下载

    已知需要用到两个插件来帮助实现
    一个是html转canvas的插件 html2canvas可通过npm下载

    npm install html2canvas -D
    
    • 1

    一个是将base64图片格式转本地地址的Dcloud插件image-tools

    1、画需要生成图片的元素

    即就是生成图片的样式 还是需要我们自己来搞出来。可以封装成一个组件形式,这里就不贴代码,因为这不是核心逻辑,况且大家需要生成图片的样式都不一样,唯一需要注意的是,这块元素是要脱离文档流,并置于屏幕外,不让用户看到

    将生成图片的代码封装成一个组件,如下 需要声明一个id 为后续转canvas做准备

    <KitcalculatorTable id="pagePoster"/>
    
    • 1

    并将这块区域通过固定定位置于可视区外,这样就看不到了,不能用v-if或者v-show、display:none去隐藏,这样在后续html转canvas是失败的,无法获取到该区域元素

    position: fixed;
    top: -999999rpx;
    background-color: #fff;
    padding: 30rpx;
    
    • 1
    • 2
    • 3
    • 4

    2将html转成canvas的形式,再转成base64图片形式

    <template>
    	<view class="html2Canvas" id="pagePoster">
          <view class="table">
            <view class="kitCalculatorName">{{ pageData.kitCalculatorName }}view>
            <KitcalculatorTable :tableData="tableData" :isSumData="true" />
            <view class="average-data">
              <view style="margin-right: 50rpx">件套平均价格:{{ pageData.averagePriceOneDesc }}view>
              <view v-if="visiblePrice2">平均价格2:{{ pageData.averagePriceTwoDesc }}view>
            view>
          view>
          <view class="bottom-logo">
            <img class="code" :src="codeImage" />
            <view>
              <view class="">报盘计算器,长按识别二维码使用view>
              <img class="logo" :src="logoImage" />
            view>
          view>
        view>
    	<view class="muji-button" style="margin: 0 24rpx" @click="canvasImage.generateImageSave">保存图片view>
    	<view class="muji-button" @click="canvasImage.generateImageShare">分享view>
    template>
    <script lang="renderjs" module="canvasImage">
    import html2canvas from 'html2canvas'
    export default {
    	mounted() {},
      methods: {
    		generateImageSave(){
    			this.generateImage('save')
    		},
    		generateImageShare(){
    			this.generateImage('share')
    		},
        // 生成图片需要调用的方法
        generateImage(methodType) {
    	  this.$ownerInstance.callMethod('openLoading', '正在生成图片~')
          setTimeout(() => {
            const dom = document.getElementById('pagePoster') // 需要生成图片内容的 dom 节点
            html2canvas(dom, {
              width: dom.clientWidth, //dom 原始宽度
              height: dom.clientHeight,
              scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
              scrollX: 0,
              useCORS: true, //支持跨域
              // scale: 2, // 设置生成图片的像素比例,默认是1,如果生成的图片模糊的话可以开启该配置项
            }).then((canvas) => {
              // 生成成功
              // html2canvas 生成成功的图片链接需要转成 base64位的url
    			this.$ownerInstance.callMethod('receiveRenderData',canvas.toDataURL('image/png'))
            }).catch(err=>{
    			this.$ownerInstance.callMethod('_errAlert',`【生成图片失败,请重试】${err}`)
            })
          }, 300)
        },
      }
    }
    script>
    <script>
    import { pathToBase64,base64ToPath} from 'image-tools';
    export default {
      props: {
        pageData: {
          type: Object,
          default: () => {
            return {};
          },
        },
      },
      data() {
        return {
          temUrl: '', //生成的临时路径图片
          codeImage: '', // 件套二维码图片
          logoImage: '', // logo图片
        };
      },
    
      created() {
        // 处理静态图片 转为base64
        this.actionImage();
      },
    
      methods: {
        // 处理已知静态图片 转base64格式
        actionImage() {
          this.turnBase64Image(require('@/static/logo/down-code.png'), 'codeImage');
          this.turnBase64Image(require('@/static/logo/muji-logo.png'), 'logoImage');
        },
        // 将图片转为base 64 位url
        turnBase64Image(img, key) {
          uni.getImageInfo({
            src: img,
            success: (image) => {
              pathToBase64(image.path)
                .then((base64) => {
                  this[key] = base64;
                })
                .catch((error) => {
                  console.log('转换失败:', error);
                });
            },
            fail: (err) => {
              console.log('将本地图片转为base 64报错:', err);
            },
          });
        },
        /* 将base64 位的图片路径转换为 临时路径 */
        loadBase64Url(imageStr) {
          const that = this;
          base64ToPath(imageStr)
            .then((path) => {
              this.temUrl = path;
    			this.closeLoading()
    			this.saveImg()
            })
            .catch((error) => {
              console.error('临时路径转换出错了:', error);
            });
        },
        // 获取生成的base64 图片路径
        receiveRenderData(val) {
          const url = val.replace(/[\r\n]/g, ''); // 去除base64位中的空格
          this.loadBase64Url(url);
        },
        // 报错alert
        _errAlert(content) {
          uni.showModal({
            title: '提示',
            content: content,
          });
        },
        saveImg() {
          uni.saveImageToPhotosAlbum({
    		filePath: this.temUrl,
    			success: function () {
    				uni.showToast('保存图片成功');
    			}
    	});
        },
      },
    };
    script>
    
    • 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
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    需要注意的两点是,这里要新建一个script节点,将语言改成renderjs的形式 在这之内做html转canvas的操作
    再就是需要把生成图片中的已知静态图片 如下载二维码、企业logo转换成base64的形式

    保存图片

    最后就是点击保存后,调用canvasImage下的generateImage去生成图片,拿到base64格式图片通过image-tools的base64ToPath方法去转成临时路径再下载就ok了

    题外话

    这里涉及到renderjs的通讯知识,还是有点坑的
    比如在renderjs模块调用script的方法是可以直接

    this.$ownerInstance.callMethod('script内方法名',需要带的参数)
    
    • 1

    目前只了解可以在dom去调用renderjs方法,在script内貌似不能直接用。大家就要根据需求去灵活使用这个东西

  • 相关阅读:
    小型架构实验模拟
    Java8 Stream流式操作接口详解
    矩阵分析与应用
    Android网络请求(1)
    何以创新和体验升维?百度输入法用虚拟博主给出了答案
    wxy创建记录
    操作系统的内存究竟是怎么一回事?
    Clion学习
    js 关于 replace 取值、替换第几个匹配项
    SpringCloud学习笔记(二)Eureka 服务注册与发现
  • 原文地址:https://blog.csdn.net/imsopoor/article/details/134412807