首页 前端知识 【uniapp vue3 html2canvas uQRcode】根据html生成画布,base64转本地路径,生成二维码,分享至微信,详细记录实现过程中的所有坑以及具体实现思路及完整代码

【uniapp vue3 html2canvas uQRcode】根据html生成画布,base64转本地路径,生成二维码,分享至微信,详细记录实现过程中的所有坑以及具体实现思路及完整代码

2024-02-11 10:02:35 前端知识 前端哥 938 597 我要收藏

2023年11月8号记录:
这个功能花费了我差不多两个整天的时间才实现,非常折磨人,中途差点放弃

uniapp+vue3+html2canvas+uQRcode即可实现功能
uniapp+vue3+html2canvas+canvas2image+uQRcode也可以实现,主要是实现的过程中以为需要这个插件,但最后发现不用也不影响,代码贴出来仅供参考

1、需求:
安卓系统+uniapp实现app端根据dom元素,生成图片其中包含头像,二维码等元素,
通过uni的系统分享,分享到微信,qq,朋友圈等

2、遇到的坑:
(1)uniapp不能直接操作dom元素,需要使用renderjs,在视图层操作dom元素
(2)vue3写法,callMethod定义的方法,无法在主script中触发,不能使用setup语法糖的写法
(3)base64如何转为本地路径,new plus.nativeObj.Bitmap(“test”)
(4)发包后报错,图片存在跨域问题 //不能使用静态图片,不能使用背景图
(5)uniapp中无法使用new Blob(),有些文章用了这个方法,但是我这里报错,Blob未定义

3、具体实现思路:
1、在模板区,需要生成画布的内容区域,最外面的标签上加上id=“poster”,需要通过id获取这个元素
2、在模板区,有背景图的话,不要写成静态的引入,比如: src=“@/static/image/bcg.png”,需要后端返才行。如果实在想尝试用本地的,可以试试写绝对路径,比如: src=“D:/app/my-demo/static/image/bcg.png”
3、在模板区,使用后端返的背景图,不能写background,用image标签接收,对应的样式代码,文末会贴
4、在模板区,要生成画布的内容区域里的所有image标签上可以加上crossorigin=“anonymous”,在我调试的过程中出现报错,
“Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported”,百度搜到的最多的两种解答是图片跨域了或者画布被污染了,我还加了其他的东西,不确定具体是哪一个生效了,都会贴出来仅供参考
5、在模板区触发生成画布的点击事件上,需要注意的是要这样写,@click=“renderScript.emitData”
这个就要提到renderjs了uniapp-renderjs跳转地址

在这里插入图片描述
主要就是uniapp不能直接操作dom,它的视图层和逻辑层是分离的。renderjs是视图层,设置script节点的lang为renderjs,这个script中的就是视图层,而主script包裹的就是逻辑层。

lang=“renderjs”是固定的,而module是可以自定义的,相当于起个名字,比如我这里写的是renderScript,在模板区的点击事件里调用写在renderScript模块里面的方法,就是@click=“renderScript.emitData”
在这里插入图片描述
6、在renderjs中,引入html2canvas,调用html2canvas()返回base64图片,如果是在页面中直接展示的话,uniapp的image标签也接收base64格式的,直接展示是完全可以的,但是我需要的是生成图片,因为我要分享到微信,qq,朋友圈等
7、html2canvas插件的使用相对简单,文末代码会贴完整的,通过callMethod将数据发送到逻辑层,也就是要去主script标签中处理数据,我这里遇到一个大坑,vue2写法的可以跳过,主要是针对vue3的,那就是方法在vue3的script中无法触发,也不是完全不触发,打印传过来的数据也能打印出来,但是调用uni的api,比如uni.chooseImage/uni.saveFile等都不触发,最后才找到原因,因为vue3的setup语法糖的原因,在script标签上直接加上setup就是语法糖的写法,不需要再将所有的方法和定义的数据一样一样return出去, 不明白为什么语法糖的写法就不行,换成export default {setup(){ return{} }} 写法就可以了
7、在主script中处理base64格式转图片,const bitmap = new plus.nativeObj.Bitmap(“test”);
nativeObj这个是HTML5+的管理系统原生对象,HTML5+规范,点击这里跳转
(1)HTML5+,简称H5+,是一种基于HTML5的移动应用开发框架,它提供了许多原生功能的扩展,可以通过JavaScript进行调用
(2)plus.nativeObj.Bitmap:这是H5+中的一个原生对象,用于操作位图(图片)的相关功能。它提供了很多方法来加载、创建、保存和处理位图。
(3)new plus.nativeObj.Bitmap(“test”):这行代码创建了一个新的位图对象,并指定了名称为"test"。这里的"test"可以是图片的文件路径或一个相对路径,用于加载现有的图片,也可以是一个名称,用于创建一个新的空白位图。
在这里插入图片描述
这里截取的是保存示例,还有load加载图片示例,clear销毁图片示例,draw绘制图片示例等,可以直接去文档上看更详细的
在这里插入图片描述
8、const url = “_doc/” + new Date().getTime() + “.png”;可以直接用,当调用保存的时候,这个url就是临时路径名
9、调用uni.saveImageToPhotosAlbum,将临时路径存放到系统相册里
10、调用plus.share.sendWithSystem(),好处就是不需要集成三方SDK,缺点就是无法分享为微信小程序
在这里插入图片描述
这里有个注意点,参数pictures数组中的图片仅支持本地路径,所以bitmap的save方法一定要调用,先保存到本地相册,然后才能获取到。我之前想省略这一步,不想每次操作的时候都要保存一张照片,然后就会报错,报“资源获取失败”的错。
在这里插入图片描述
11、关于生成二维码的插件,如果没用特殊的要求,直接在Hbuilder的插件市场搜uQRcode,我找插件的时候发现这款插件下载量非常高,维护的挺好的,使用也很简单
在这里插入图片描述
示例代码贴的非常全,我就是直接复制拿过来用的

在这里插入图片描述

uniapp+vue3+html2canvas+uQRcode实现的完整代码:

npm i html2canvas
<template>
	<view class="container" id="poster">
	//接口获取背景图片的代码没写,就是非常简单的调接口,拿图片地址
	<image :src="data.bcgPng" mode="" class="img-bcg" crossorigin="anonymous"></image>
	//需要生成画布的内容区域.....
	<view>
	<image class="avatar" :src="data.avatar" mode="aspectFill" crossorigin="anonymous"></image>
	<canvas id="qrcode" canvas-id="qrcode" style="width: 160px;height: 160px;margin:auto"></canvas>
</view>
	</view>

	<view class="bottom-box" @click="renderScript.emitData">			
			<view class="text">
				点击分享
			</view>
		</view>
</template>

css样式,关于背景图

.img-bcg {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			z-index: -1;
		}

<script module="renderScript" lang="renderjs">
	import html2canvas from 'html2canvas';
	export default {
		data() {
			return {}
		},
		mounted() {},
		methods: {
			// 发送数据到逻辑层
			emitData(e, ownerVm) {
				const dom = document.getElementById('poster')
				html2canvas(dom, {
					width: dom.clientWidth, //dom 原始宽度
					height: dom.clientHeight,
					scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
					scrollX: 0,
					useCORS: true, //支持跨域
					allowTaint: true, // 允许跨域图片
				}).then((canvas) => {
				//callMethod将数据发送到主script中
					ownerVm.callMethod('receiveRenderData', canvas.toDataURL('image/png'))
				});

			}
		}
	};
</script>
<script>
import {	
		onReady
	} from "@dcloudio/uni-app";
	import UQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js';
export default {
		setup() {
		onReady(() => {
				// 获取uQRCode实例
				var qr = new UQRCode();
				// 设置二维码内容
				// qr.data = "https://uqrcode.cn/doc";
				qr.data = "uid200";
				// 设置二维码大小,必须与canvas设置的宽高一致
				qr.size = 200;
				// 调用制作二维码方法
				qr.make();
				// 获取canvas上下文
				var canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入
				// 设置uQRCode实例的canvas上下文
				qr.canvasContext = canvasContext;
				// 调用绘制方法将二维码图案绘制到canvas上
				qr.drawCanvas();
			})
			function receiveRenderData(val) {
				var base64 = val;
				const bitmap = new plus.nativeObj.Bitmap("test");
				bitmap.loadBase64Data(base64, function() {
					const url = "_doc/" + new Date().getTime() + ".png"; // url为时间戳命名方式
					bitmap.save(url, {
						overwrite: true, // 是否覆盖
					    quality: 'quality'  // 图片清晰度
					}, (i) => {
						uni.saveImageToPhotosAlbum({
							filePath: url,
							success: function() {
								plus.share.sendWithSystem({
									content: '分享内容',
									type: 'image',
									pictures: [url]
								}, function() {
									console.log('分享成功');
								}, function(e) {
									console.log('分享失败:' + JSON.stringify(e));
								});
							
								bitmap.clear()
							}
						});
					}, (e) => {
						uni.showToast({
							title: '图片保存失败',
							icon: 'none'
						})
						bitmap.clear()
					});
				}, (e) => {
					uni.showToast({
						title: '图片保存失败',
						icon: 'none'
					})
					bitmap.clear()
				});
			}
			return {			
				receiveRenderData,
			};
		}

	}
</script>

uniapp+vue3+html2canvas+uQRcode+canvas2image实现的完整代码,仅供参考:

<template>
	<view class="container" id="poster">
	//需要生成画布的内容区域.....
	<canvas id="qrcode" canvas-id="qrcode" style="width: 160px;height: 160px;margin:auto"></canvas>
	</view>
	//canvas2image会直接在页面中生成canvas画布绘制出来的图片
	//如果需要在页面中展示,可以使用这个插件,另行优化
	//uniapp提供的image标签也能接收base格式,所以这个canvas2image没在我这里发挥最大的价值
		<view class="imageShow" id="Image" style="display: none;">
		</view>
	<view class="bottom-box" @tap="renderScript.emitData">			
			<view class="text">
				点击分享
			</view>
		</view>
</template>
<script module="renderScript" lang="renderjs">
	import html2canvas from 'html2canvas';
	import Canvas2Image from 'canvas2image'
	export default {
		data() {
			return {}
		},
		mounted() {},
		methods: {
			// 发送数据到逻辑层
			emitData(e, ownerVm) {
				let domObj = document.getElementById("poster");
				//获取到DOM节点的位置
				let width = domObj.offsetWidth;
				let height = domObj.offsetHeight;
				//DOM元素的宽高
				let canvas = document.createElement("canvas")
				//创建canvas
				let scale = 5
				//放大比例设置5倍
				canvas.width = width * scale
				canvas.height = height * scale
				//画板的宽高
				let options = {
					logging: true,
					//日志开关,在控制台可以查看html2canvas的内部执行流程
					width: width,
					height: height,
					//避免下载不全
					useCORS: true,
					//【重要】开启跨域配置
					scale: scale,
					canvas: canvas,
					//自定义属性
				}
				html2canvas(domObj, options).then((canvas) => {
					let context = canvas.getContext('2d')
					//关闭锯齿
					context.mozImageSmoothingEnabled = false
					context.webkitImageSmoothingEnabled = false
					context.msImageSmoothingEnabled = false
					context.imageSmoothingEnabled = false

					let img = Canvas2Image.convertToJPEG(canvas, canvas.width, canvas.height)
					// 这就是把canvas转化为图片
					document.getElementById('Image').appendChild(img);
					//展示图片的DOM节点
					img.style.width = canvas.width / 5 + 'px';
					img.style.height = canvas.height / 5 + 'px';
					const src = img.getAttribute('src')
					ownerVm.callMethod('receiveRenderData', src)
				})
			}
		}
	};
</script>
<script>
import {	
		onReady
	} from "@dcloudio/uni-app";
	import UQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js';
export default {
		setup() {
		onReady(() => {
				// 获取uQRCode实例
				var qr = new UQRCode();
				// 设置二维码内容
				// qr.data = "https://uqrcode.cn/doc";
				qr.data = "uid200";
				// 设置二维码大小,必须与canvas设置的宽高一致
				qr.size = 200;
				// 调用制作二维码方法
				qr.make();
				// 获取canvas上下文
				var canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入
				// 设置uQRCode实例的canvas上下文
				qr.canvasContext = canvasContext;
				// 调用绘制方法将二维码图案绘制到canvas上
				qr.drawCanvas();
			})
			function receiveRenderData(val) {
				var base64 = val;
				const bitmap = new plus.nativeObj.Bitmap("test");
				bitmap.loadBase64Data(base64, function() {
					const url = "_doc/" + new Date().getTime() + ".png"; // url为时间戳命名方式
					bitmap.save(url, {
						overwrite: true, // 是否覆盖
					    quality: 'quality'  // 图片清晰度
					}, (i) => {
						uni.saveImageToPhotosAlbum({
							filePath: url,
							success: function() {
								plus.share.sendWithSystem({
									content: '分享内容',
									type: 'image',
									pictures: [url]
								}, function() {
									console.log('分享成功');
								}, function(e) {
									console.log('分享失败:' + JSON.stringify(e));
								});
							
								bitmap.clear()
							}
						});
					}, (e) => {
						uni.showToast({
							title: '图片保存失败',
							icon: 'none'
						})
						bitmap.clear()
					});
				}, (e) => {
					uni.showToast({
						title: '图片保存失败',
						icon: 'none'
					})
					bitmap.clear()
				});
			}
			return {			
				receiveRenderData,
			};
		}

	}
</script>
转载请注明出处或者链接地址:https://www.qianduange.cn//article/1719.html
评论
发布的文章

Jquery-day01

2024-02-25 11:02:14

Jquery的基本认识

2024-02-25 11:02:11

浏览器调用摄像头

2024-02-25 11:02:09

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!