没有套路,没有难读的文档,直接看代码
html部分
<template>
<canvas type="2d" id="myCanvas" />
<canvas canvas-id="myCanvas" id="myCanvas">canvas>
<button @click="drawCanvas">绘制canvasbutton>
<button @click="preservation">保存到本地button>
template>
js部分
<script>
export default {
data() {
return {
textCanvas: null, // 初始化 canvas 值
}
},
methods: {
// 绘制canvas
drawCanvas() {
// 指定this的指向
let that = this;
// uni-app 中,不管是小程序,app,h5 在获取元素实例时,都是统一的方法,只要获取元素的宽高
uni.createSelectorQuery().select('#myCanvas').fields({ node: true, size: true })
.exec((res) => {
// #ifdef MP-WEIXIN
// 获取设备设备像素比
const dpr = uni.getSystemInfoSync().pixelRatio;
// 微信小程序绘制
let textCanvas = that.textCanvas = res[0].node; // 获取元素实例
textCanvas.width = res[0].width * dpr; // 设置canvas像素宽
textCanvas.height = res[0].height * dpr; // 设置canvas像素高
let textCtx = textCanvas.getContext('2d'); // 创建二维绘图
textCtx.clearRect(0, 0, res[0].width, res[0].height); // 设置画布大小
textCtx.beginPath(); // 创建一条新的路劲
textCtx.scale(dpr, dpr); // 设置x,y缩放(这里作用不大,,没效果)
// 这里开始绘制canvas内容,绘制的过程当中,不知道是小程序的问题,还是什么问题在绘制有背景图片的内容时,
// 文字内容必须要延迟绘制,也就是要定时器延迟一定时间才能绘制,要不然就会将文字覆盖在图片下方。
// 图片的绘制
const tx = textCanvas.createImage();
tx.src = "../../.."; // 线上地址或者本地地址都可以
tx.onload = () => {
textCtx.drawImage(tx, 20, 20, 100, 100); // 参数从左到右说明, 图片文件,x轴开始位置,y轴开始位置,x轴结束位置,y轴结束位置
};
// 文字设置
textCtx.fillStyle = "#3085FC"; // 文字颜色
textCtx.font = "14px sans-serif"; // 字体样式 设置加粗("normal bold 16px sans-serif");
textCtx.fillText("内容", 160, 45); // 设置文字内容, x轴位置,y轴位置
// 设置分割线
textCtx.moveTo(10, 130); // 设置线条开始位置x,y
textCtx.lineTo(res[0].width - 10, 130); // 设置线条结束位置x,y
textCtx.lineWidth = 1; // 设置线条粗细
textCtx.strokeStyle = "#e7e7e7"; // 设置线条颜色
textCtx.stroke(); // 重点,不写线条不显示
// ... // 其他设置自己查文档很简单
// #endif
// #ifdef APP-PLUS || H5
// app 和 h5 的设置方式是一样的
let tcx = uni.createCanvasContext('myCanvas'); // 通过canvasId 创建画布
// 设置图片,如果是背景图,就通过获取的实例,获取到他的宽高直接使用
tcx.drawImage('../../../static/imgage/abc.png', 0, 0, res[0].width, res[0].height);
// 文字和分割线设置和小程序无异
tcx.draw(); // 将设置的内容绘制出来,不写不显示
// #endif
})
},
// 保存canvas 到本地
preservation() {
// 指定 this 指向
let that = this;
// #ifdef MP-WEIXIN
// 在微信中保存canvas为图片到本地,要通过canvas 实例的参数进行设置
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: that.textCanvas.width, // 设置画布宽度
height: that.textCanvas.height, // 设置画布高度
destWidth: that.textCanvas.width, // 屏幕width像素密度设置
destHeight: that.textCanvas.height, // 屏幕height像素密度设置
canvas: that.textCanvas, // 这里是重点,获取实例的时候保存为全局变量就行了
// 这里使用的 textCanvas 在 vue2 中定义在data中没有问题,但是在vue3中,使用响应式时一定要注意定义的变量不要使用响应式定义,微信小程序会一直报错,直接使用 let textCanvas 定义
complete(res) {
// res.tempFilePath 返回的是临时地址 png 或者 jpg
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success() {
uni.showToast({
title: "保存成功",
icon: "success"
})
},
fail() {
uni.showToast({
title: "保存失败",
icon: "error"
})
}
});
}
})
// #endif
// #ifdef APP-PLUS || H5
// app 和 h5 获取元素的方式都相同
uni.canvasToTempFilePath({
canvasId: "myCanvas",
complete(res) {
// #ifdef APP-PLUS
// 在 app 中, 图片地址直接返回的值 临时地址 png 或 jpg,直接使用uni的方法
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success() {
uni.showToast({
title: "保存成功",
icon: "success"
});
},
fail() {
uni.showToast({
title: "保存失败",
icon: "error"
})
}
})
// #endif
// #ifdef H5
// 在 h5 中,res.tempFilePath 返回的是 base64 类型要处理,通过 a 标签的形式下载
var arr = res.tempFilePath.split(',');
var bytes = atob(arr[1]);
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
var blob = new Blob([ab], { type: 'application/octet-stream' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = new Date().valueOf() + ".png";
var e = document.createEvent('MouseEvents');
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
URL.revokeObjectURL(url);
// #endif
}
})
}
}
}
</script>