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

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

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

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

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

<KitcalculatorTable id="pagePoster"/>

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

position: fixed;
top: -999999rpx;
background-color: #fff;
padding: 30rpx;

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>

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

保存图片

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

题外话

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

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

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

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值