使用前注意点:(若不添加,则无法渲染到canvas中)以下是我未注意踩到的坑:
1、当使用image时,一定要在image标签上添加data-type与data-url属性;
2、当使用文本时,一定要在文本标签上添加data-type与data-text属性;
3、若节点中的图片存在缩放,目前(v1.0.1)暂时对css3中的scale还不够友好,建议将计算好的放大倍数直接与目标图片的宽高相乘计算;
4、如果想通过id获取canvas的节点属性,一定要在设置canvas-id的同时也要设置id,目前我通过wx.createSelectorQuery.select(“canvas-id”)无法获取到想要的结果;select方法最好是选择id值;
5、data-delay:标签属性,用于控制渲染节点的顺序;
官方wxml2canvas文档地址:https://www.npmjs.com/package/wxml2canvas
指定节点生成图片并下载到本地:
npm i wxml2canvas
之后打开微信开发者中选择工具项—选择构建npm;(否则无法在小程序环境中使用)
import wxml2canvas from "wxml2canvas";
wxml:
<canvas canvas-id="myCanvas" id="canvasId"></canvas>
<view id="my-canvas" class="my_canvas>
<view class="header draw_pnode">
<!-- data-delay: 可以控制节点渲染的层级 -->
<image class="headerImg draw_cnode" src="{{order.headerImg}}" data-type="image" data-url="{{order.headerImg}}" data-delay={{1}}></image>
<text class="headerTitle draw_cnode" data-type="text" data-text="您的订单详情">您的订单详情</text>
</view>
</view>
划重点:我现在的目标是绘制class="headerImg"下的所有节点信息,注意每个节点标签上的类名;后面会提到;
js:
获取canvas的宽高后开始绘制
drawMyCanvas() {
wx.showLoading();
const that = this;
const query = wx.createSelectorQuery().in(this);
query
.select("#canvasId")
.fields({
// 选择需要生成canvas的范围
size: true,
node: true, // 获取节点信息
})
.exec((data) => {
let cvsWidth = data.width;
let cvsHeight = data.height;
that.setData({
cvsWidth,
cvsHeight,
});
setTimeout(() => {
that.startDraw();
}, 500);
});
},
开始绘制canvas画布并保存图片
startDraw() {
let that = this;
// 创建wxml2canvas对象
let drawMyImage = new Wxml2Canvas(
{
element: "canvasId", // canvas的id,
obj: that, // 传入当前组件的this
width: that.data.width, // canvas画布宽度
height: that.data.height, // canvas画布高度
background: "#fff", // 生成图片的背景色
progress(percent) {
// 进度
// console.log(percent);
},
finish(url) {
// 生成的图片
wx.hideLoading();
that.savePoster(url);
},
error(res) {
// 失败原因
console.log(res);
wx.hideLoading();
},
},
this
);
let data = {
// 获取wxml数据
list: [
{
type: "wxml",
class: ".draw_pnode .draw_node", // draw_pnode要绘制的wxml元素根类名, draw_node单个元素的类名(所有要绘制的单个元素都要添加该类名)
limit: ".draw_pnode", // 要绘制的wxml元素根类名,也就是指定要绘制哪些父级中的元素
x: 0,
y: 0,
},
{
type: "text",
text: "添加你需要的文案",
delay: true, // 延迟渲染,确保渲染在别的节点上方
x: 40, // 相对于画布的x轴位置
y: 275, // 相对于画布的y轴位置
style: {
fontSize: 14,
lineHeight: 20,
fontFamily: "PingFangSC-Regular",
},
}
],
};
// 绘制canvas
drawMyImage.draw(data, this);
},
属性解读:
class: “.draw_pnode .draw_node”:draw_pnode 要绘制的wxml元素根类名, draw_node单个元素的类名(所有要绘制的单个元素都要添加该类名)
保存图片并请求用户授权
savePoster(url) {
const that = this;
wx.saveImageToPhotosAlbum({
filePath: url,
success: function () {
wx.showToast({
title: "保存成功",
icon: "none",
duration: 1500,
});
},
fail(err) {
if (
err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" ||
err.errMsg === "saveImageToPhotosAlbum:fail auth deny" ||
err.errMsg === "saveImageToPhotosAlbum:fail authorize no response"
) {
wx.showModal({
title: "提示",
content: "需要您授权保存相册",
showCancel: false,
success: (modalSuccess) => {
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting["scope.writePhotosAlbum"]) {
wx.saveImageToPhotosAlbum({
filePath: that.data.imgUrl,
success: function () {
wx.showToast({
title: "保存成功",
icon: "success",
duration: 2000,
});
},
});
} else {
wx.showToast({
title: "授权失败,请稍后重新获取",
icon: "none",
duration: 1500,
});
}
},
});
},
});
}
},
});
},
/**
* 获取用户保存相册权限
*/
getPhotosAuthorize: function () {
let self = this;
wx.getSetting({
success(res) {
console.log(res);
if (!res.authSetting["scope.writePhotosAlbum"]) {
wx.authorize({
scope: "scope.writePhotosAlbum",
success() {
console.log("授权成功");
self.saveImg();
},
//用户拒绝
fail() {
console.log("用户再次拒绝");
},
});
} else {
self.saveImg();
}
},
});
},
/**
* 保存到相册
*/
async saveImg() {
let self = this;
const query = wx.createSelectorQuery();
const canvasObj = await new Promise((resolve, reject) => {
query
.select("#canvasId")
.fields({ node: true, size: true })
.exec(async (res) => {
resolve(res[0].node);
});
});
console.log(canvasObj);
wx.canvasToTempFilePath(
{
//fileType: 'jpg',
//canvasId: 'posterCanvas', //之前的写法
canvas: canvasObj, //现在的写法
success: (res) => {
console.log(res);
self.setData({ canClose: true });
//保存图片
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function (data) {
wx.showToast({
title: "已保存到相册",
icon: "success",
duration: 2000,
});
fail: function (err) {
console.log(err);
if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") {
console.log("当初用户拒绝,再次发起授权");
} else {
util.showToast("请截屏保存");
}
},
complete(res) {
wx.hideLoading();
console.log(res);
},
});
},
fail(res) {
console.log(res);
},
},
this
);
},