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内貌似不能直接用。大家就要根据需求去灵活使用这个东西

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/148471.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【广州华锐互动】AR技术为气象站远程监控及在线指导维修提供极大便利

随着科技的不断发展&#xff0c;人类对于自然环境的理解和掌控能力也在不断提升。其中&#xff0c;AR&#xff08;增强现实&#xff09;技术的应用&#xff0c;为气象监控带来了革命性的变化。AR远程气象监测&#xff0c;就是将AR技术与气象监控相结合&#xff0c;通过虚拟与现…

Centos7 单用户模式修改密码 3步搞定 666 (百分比成功)

1.第一步重新服务器 2.进入这个页面按e进入单用户模式 3.找到linux16这行 在后面添加 init/bin/bash 按ctrlx进入 4.注意是事项直接修改是报错passud: Authentication token manipulation error 需要执行权限&#xff1a;mount -o remount,rw /

Scala---数据基础

一、数据类型 二、变量和常量的声明 定义变量或者常量的时候&#xff0c;也可以写上返回的类型&#xff0c;一般省略&#xff0c;如&#xff1a;val a:Int 10常量不可再赋值 1./** 2. * 定义变量和常量 3. * 变量 :用 var 定义 &#xff0c;可修改 4. * 常量 :用 val 定…

最快最便捷的pytest使用allure测试报告

一、前言 最近通过群友了解到了allure这个报告&#xff0c;开始还不以为然&#xff0c;但还是逃不过真香定律。 经过试用之后&#xff0c;发现这个报告真的很好&#xff0c;很适合自动化测试结果的展示。下面说说我的探索历程吧。 选用的项目为Selenium自动化测试Pytest框架实…

IP地址查询在社交行业中的崭新应用

在社交媒体蓬勃发展的今天&#xff0c;IP地址查询技术IP66_ip归属地在线查询_免费ip查询_ip精准定位平台正在成为社交行业中的一项强大工具。这项技术不仅为社交平台提供了更多个性化服务的可能&#xff0c;还在用户安全和内容管理等方面发挥了关键作用。本文将深入探讨IP地址查…

代码随想录算法训练营第21天|530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先

JAVA代码编写 530.二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&#xff1a; 输入&#xff1a;root [4,2,6,1,3] 输出&#xff1a;1…

使用Halcon的HsmartWindows窗体控件显示3D模型

在此之前可以先浏览我的LMI&#xff08;3D&#xff09;SDK配合学习 https://blog.csdn.net/m0_51559565/article/details/134419165 //配置LMI相机 https://blog.csdn.net/m0_51559565/article/details/134404394 //LMI相机SDK https://www.51halcon.com/forum.php?modviewthr…

steam搬砖核心原理是什么?为什么会有差价产生?

CSGO游戏搬砖到底怎么赚钱的&#xff0c;赚钱原理讲解 这涉及到一个关于汇率差异的知识点。众所周知&#xff0c;目前1美元7.2元&#xff0c;但实际上我们在steam账户里拿到1美元&#xff0c;实际上只需要5.4元左右&#xff0c;也就是说&#xff0c;如果这款产品是steam和网易两…

如何使用iPhone15在办公室观看家里电脑上的4k电影?

如何使用iPhone15在办公室观看家里电脑上的4k电影&#xff1f; 文章目录 如何使用iPhone15在办公室观看家里电脑上的4k电影&#xff1f;1.使用环境要求&#xff1a;2.下载群晖videostation&#xff1a;3.公网访问本地群晖videostation中的电影&#xff1a;4.公网条件下使用电脑…

[Linux] DHCP网络

一、DHCP服务 1.1 DHCP的简介 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;通常被应用在大型的局域网络环境中&#xff0c;主要作用是集中地管理、分配IP地址&#xff0c;使网络环境中的主机动态的获得IP地址、Gateway地址…

不能错过的2个方法,轻松学会如何备份系统!

​天有不测风云&#xff0c;电脑也有旦夕祸福&#xff0c;谁也不能预料到未来会发生什么意外状况&#xff0c;为了防止系统故障而导致的数据丢失和系统崩溃状况&#xff0c;学会定期备份系统是很重要的。 那么我们该如何备份系统呢&#xff1f;方法其实还是有很多种…

Python基础-解释器安装

一、下载 网址Welcome to Python.orgPython更新到13了&#xff0c;我们安装上一个12版本。 这里我保存到网盘里了&#xff0c;不想从官网下的&#xff0c;可以直接从网盘里下载。 链接&#xff1a;百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间…

python+django+mysql个人博客项目部署(VMware部署)

目录 一、Vmware新建win7虚拟机 二、组件/软件安装 2.1 安装python3 2.2 更新pip 2.3 安装pycharm 2.4 安装django 2.5 win安装mysql 三、配置数据库 3.1 安装sqlite客户端 3.2 db.sqlite3导出为myblog.sql 3.3 Heidisql连接本地sql 四、部署项目 4.1 安装模块 4.2 尝试运行 …

Python自动化测试之request库详解(二)

http协议是无状态的&#xff0c;也就是每个请求都是独立的。那么登录后的一系列动作&#xff0c;都需要用cookie来验证身份是否是登录状态&#xff0c;为了高效的管理会话&#xff0c;保持会话&#xff0c;于是就有了session。 session简介 session是一种管理用户状态和信息的…

2024年软件测试知识应运趋势

每一年&#xff0c;IT互联网技术都在变&#xff0c;那2024年&#xff0c;需要具备哪些知识&#xff0c;才能让我们在软件测试行业里混得风生水起呢&#xff1f; 我认为有以下十点&#xff1a; 1、Linux必备知识 Linux作为现在最流行的软件环境系统&#xff0c;一定需要掌握&am…

vue3+webpack+elementplus+国际化+axios封装+pinia

文章目录 创建项目 eslint prettier切换pinia&#xff08;后补上&#xff09;创建项目eslint prettier注意 自动格式化 element plus注意 element plus icon注意&#xff1a; 国际化注意 axios 封装 最近菜鸟自己搭建一个项目&#xff0c;想着 vue3 都出来这么久了&#xff…

每日一题 2656. K 个元素的最大和(简单)

感觉每日一题除了困难之外很久没有做到有营养的题了 class Solution:def maximizeSum(self, nums: List[int], k: int) -> int:return (2 * max(nums) k - 1) * k // 2

推荐一个Node.js多版本管理的可视化工具

关于Node.js的开发者来说&#xff0c;在开发机器上管理多个不同版本的Node.js是一个常见痛点。之前在开发者安全大全专栏中&#xff0c;提到过解决方法&#xff1a;使用nvm&#xff0c;如果对于nvm还不了解的话&#xff0c;可以前往了解。 对于TJ来说&#xff0c;因为习惯敲命…

漏洞复现--迪普DPTech VPN 任意文件读取

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

计讯物联LoRa终端TW820多重优势共蓄能,强力驱动行业发展

LoRa&#xff0c;即远距离无线电&#xff0c;是一种低功耗宽区域网络(LPWAN)的通信技术。它在同样的功耗条件下比其他无线方式传播的距离更远&#xff0c;且比传统的无线射频通信距离扩大3-5倍&#xff0c;真正实现了低功耗、远距离、广覆盖的统一。基于LoRa通信技术的优势特点…