uniapp_canvas_vue2绘制图片及文字组件

一、在 components 中新建 canvasCom 文件夹并新建 canvasCom.vue 文件
1、写入 html 代码
<template>
	<view class="wrap" :style="'width:' + width + 'px;height: ' + height + 'px;'">
		<image class="img" :src="imageSrc"></image>
		<canvas class="canvas" canvas-id="myCanvas" id="myCanvas"
			:class="isPointerEvents ? 'pointerEvents' : 'noPointerEvents'" @longtap="longtap"></canvas>
	</view>
</template>
2、写入 css 代码
.wrap {
	position: relative;

	.img,
	.canvas {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
	}

	.pointerEvents {
		pointer-events: all;
	}

	.noPointerEvents {
		pointer-events: none;
	}
}
3、写入 js 代码
export default {
	name: "canvasCom",
	props: {
		// 宽 --- 数值
		width: {
			type: Number,
			default: 300
		},
		// 高 --- 数值
		height: {
			type: Number,
			default: 300
		},
		// 元素 --- 数组对象
		info: {
			type: Array,
			default: []
		}
	},
	data() {
		return {
			// 图片
			imageSrc: '',
			// 是否可触摸
			isPointerEvents: false,
			// 判断平台
			type: uni.getSystemInfoSync(),
		};
	},
	mounted() {
		// 绘制
		this.drawImage();
		// 判断平台
		if (this.type.uniPlatform == 'mp-weixin') {
			this.isPointerEvents = true;
		} else if (this.type.uniPlatform == 'web') {
			// 开启后 h5 可以使用系统长按功能
			this.isPointerEvents = false;
		}
	},
	methods: {
		// 绘制图片
		async drawImage() {
			const ctx = uni.createCanvasContext('myCanvas', this);
			ctx.drawImage(await this.baseFun(this.info[0].src), this.info[0].x == 'center' ? await this.centerImg(
				this.width, this
				.info[0].width) : this.info[0].x, this.info[0].y, this.info[0].width, this.info[0].height);
			ctx.drawImage(await this.baseFun(this.info[1].src), this.info[1].x == 'center' ? await this.centerImg(this.width, this
				.info[1].width) : this.info[1].x, this.info[1].y, this.info[1].width, this.info[1].height);
			ctx.drawImage(await this.baseFun(this.info[4].src), this.info[4].x == 'center' ? await this.centerImg(
				this.width, this
				.info[4].width) : this.info[4].x, this.info[4].y, this.info[4].width, this.info[4].height);

			// 设置字体样式
			ctx.font = this.info[2].font;
			// 设置文本颜色
			ctx.fillStyle = this.info[2].fillStyle;
			// 绘制文本
			let text = this.info[2].content;
			ctx.fillText(text, await this.centerText(text, ctx), 50);

			ctx.font = this.info[3].font;
			ctx.fillStyle = this.info[3].fillStyle;
			let text_ = this.info[3].content;
			ctx.fillText(text_, await this.centerText(text_, ctx), 100);

			ctx.draw(false, () => {
				uni.canvasToTempFilePath({
					canvasId: 'myCanvas',
					success: (res) => {
						this.imageSrc = res.tempFilePath;
					},
					fail: (err) => {
						console.error('Canvas to temp file path failed: ', err);
					}
				}, this);
			});
		},
		// 将图片转换为 base64
		baseFun(url) {
			let isImg = /^https?:\/\//i;
			return new Promise((resolve, reject) => {
				if (isImg.test(url)) {
                      // 网络图片
					uni.request({
						url: url,
						responseType: 'arraybuffer',
						success: (res) => {
							let base64Img = 'data:image/jpeg;base64,' + uni.arrayBufferToBase64(res
								.data);
							resolve(base64Img);
						},
						fail: (err) => {
							reject(err);
						}
					});
				} else {
                      // 本地图片
					resolve(url);
				}
			})
		},
		// 计算文字居中
		centerText(str, ctx) {
			return new Promise((resolve, reject) => {
				const query = uni.createSelectorQuery().in(this);
				query.select('#myCanvas').boundingClientRect(data => {
					let textWidth = ctx.measureText(str).width;
					let width = data.width / 2 - textWidth / 2;
					if (width) {
						resolve(width);
					} else {
						reject('获取失败')
					}
				}).exec();
			})
		},
		// 计算图片居中
		centerImg(domWidth, imgWidth) {
			return new Promise((resolve, reject) => {
				let width = domWidth / 2 - imgWidth / 2;
				if (width) {
					resolve(width);
				} else {
					reject('获取失败')
				}
			})
		},
		// 长按事件
		longtap() {
			console.log('长按');
			if (this.type.uniPlatform == 'mp-weixin') {
				// 微信小程序长按保存
				uni.saveImageToPhotosAlbum({
					filePath: this.imageSrc,
					success: function() {
						console.log('save success');
					}
				});
			}
		},
	}
}

注:经过尝试,目前还没有更好的方案将 info 自动化绘制,各位大佬有好的方案可评论或私信分享,感谢!

二、父组件调用
1、html 代码
<canvas-com :width="width" :height="height" :info="info"></canvas-com>
2、js 代码
import canvasCom from '@/components/canvasCom/canvasCom.vue';
export default {
	data() {
		return {
			width: 300,
			height: 300,
			info: [{
					type: 'img',
					src: '/static/logo.png',
					width: 300,
					height: 300,
					x: 0, // center --- 居中 其他值可以为数值
					y: 0
				},
				{
					type: 'img',
					src: '/static/logo.png',
					width: 100,
					height: 100,
					x: 'center', // center --- 居中 其他值可以为数值
					y: 100
				},
				{
					type: 'text',
					content: '主标题',
					font: 'bold 20px Arial',
					fillStyle: '#000000',
					x: 'center', // center --- 居中 其他值可以为数值
					y: 50
				},
				{
					type: 'text',
					content: '副标题',
					font: 'bold 15px Arial',
					fillStyle: '#666666',
					x: 'center', // center --- 居中 其他值可以为数值
					y: 100
				},
				{
					type: 'img',
					src: 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/logo.png',
					width: 161,
					height: 56,
					x: 'center', // center --- 居中 其他值可以为数值
					y: 240
				}
			]
		};
	},
	components: { canvasCom },
}
三、效果展示

效果图

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值