本篇文章适用于保存用户主页、海报等至手机相册,内容包含圆角头像、文字超出显示省略号、多行超出显示省略号!(整体代码放入最下方可直接复制查看)
话不多说上图
页面如下
保存相册之后如下
整体分三部分来讲,分为wxml、wxss、js,主讲js!!!
wxml
页面除了canvas还有其他元素主要就是想让页面看起来不那么难看
<view class="canvasBox">
<canvas canvas-id='myCanvas' style='width:{{canvasWidth}}px;height: {{canvasHeight}}px;'></canvas>
</view>
<view bindtap="saveHomepage" hover-class="btnHover" class="btn">保存主页</view>
wxss
在页面上加上样式
page {
background-color: antiquewhite;
}
.canvasBox {
display: flex;
justify-content: center;
padding: 20px 0;
}
.btn {
width: 100px;
height: 42px;
background: #FFD401;
border-radius: 22px;
margin: 0 auto;
line-height: 42px;
text-align: center;
}
.btnHover {
opacity: .7;
}
以上两部分没什么说的。
主要还是js
data里面放了canvas的宽高,因为下面也有用到,如果改的话只需要改动data就行了
data: {
canvasWidth: 250,
canvasHeight: 250
}
声明一个函数 getCanvasImg(canvasId) 用来生成canvas主页;
参数canvasId:canvas的id;
主页绘制顺序是先把名字、简介绘制上去最后再去绘制圆形头像;
首先获取canvas的宽高并且给canvas一个白色的背景
let {
canvasWidth,
canvasHeight
} = this.data;
let ctx = wx.createCanvasContext(canvasId);
//给canvas一个白色背景
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fill();
将名字绘制指定位置,声明字体颜色、行高等通用变量;
名字水平居中显示,通过canvas的宽的1/2减去名字宽度的1/2;
canvas的measureText()方法返回指定字符串的一个对象包含宽度可以用measureText(str).width获取
let fontColor = "#333333"; //字体颜色
let lineHeight = 25; //文字行高
let nameMove = '《龙猫》';
ctx.font = 'normal 16px Arial';
ctx.setFillStyle(fontColor);
// 名字居中显示
ctx.fillText(nameMove, canvasWidth / 2 - ctx.measureText(nameMove).width / 2, 140);
此时的canvas如图
接下来是主页简介部分:
canvas没有给定方法可以让文字自动换行、超出显示省略号。
我们可以通过measureText()方法获取字符串的长度进行操作
看下面这个方法
封装一个函数textSplit(ctx, text, lineWidth, lines);
ctx:页面的canvas
text:需要分割的文本
lineWidth:canvas上显示文本的宽度
lines:指定行数显示省略号
方法描述:
1.通过measureText()方法获取字符串的长度;
2.根据你要在canvas上要显示的文本宽度进行判断;
3.把字符串分割通过一个字符一个字符相加获取长度,与你要显示的长度进行比较,如果大于切割,暂存数组,继续判断;多行还要进行,行数判断,当达到最后一行时,判断暂存数组的最后一个,长度是否还大于要显示的长度,如果大于进行切割拼接省略号,然后return返回。
//根据文字分割
textSplit(ctx, text, lineWidth, lines) {
if (ctx.measureText(text).width < lineWidth) {
return [text]
} else {
let textArr = []; //暂存数组
let c_text = ''; //字符拼接之后的字符串
for (let i = 0; i < text.length; i++) {
if (ctx.measureText(c_text).width < lineWidth) { //字符拼接获取宽度进行判断
c_text += text[i]
} else {
//行数判断
if (textArr.length < lines) {
textArr.push(c_text)
c_text = text[i];
} else if (textArr.length == lines) {
let c_str = textArr[lines - 1];
c_str = c_str.slice(0, c_str.length - 3) + '...'
textArr[lines - 1] = c_str;
return textArr
} else {
return textArr
}
}
};
textArr.push(c_text);
return textArr
}
}
对主页简介文字绘制
//封装一个函数,ctx:获取的canvas,maskText传的字符串,250:所需要的宽度,2:超出指定行数显示省略号
let maskText = '宫崎骏的《龙猫》你看懂了吗?带你寻找隐藏的教育意义!如果你在下雨天的车站,遇到被淋湿的妖怪,请把雨伞借给它,你会得到森林的通行证哦!'; //文字
let showText = this.textSplit(ctx, maskText, 230, 2);
console.log(showText);
showText.forEach((item,index)=>{
ctx.font = 'normal 14px Arial';
ctx.setFillStyle(fontColor);
ctx.fillText(item,15 , 170 + index*lineHeight);
})
到这里,简介文字已经绘制完毕,看一下效果
接下来就是头像
canvas同样没有直接给绘制圆形头像的方法,我们可以通过arc()画圆,通过clip()剪切圆形区域,只有圆形区域可见,这样就形成了圆形头像。
// 头像居中显示
ctx.save();
ctx.beginPath();
ctx.arc(canvasWidth / 2, 65, 40, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage('/image/02.png', 50, 0, 200, 200);
ctx.restore()
到这之后canvas主页就已经绘制完毕了
接下来就是如何将绘制的主页保存至手机上
还是一样弄个函数
saveHomepage()保存主页
方法描述:
1.通过wx.getSetting()判断当前小程序是否有保存相册的权限;
2.如果有,调用 wx.saveImageToPhotosAlbum()直接保存;
3.如果没有,调用wx.authorize()向用户发起相册授权请求;
4.如果授权允许,调用 wx.saveImageToPhotosAlbum()直接保存;
5.如果拒绝授权给个弹窗提示
// 保存
saveHomepage(){
let that = this;
//判断当前小程序是否有保存相册的权限
wx.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success(res) {
that.startSaveImage();
},
fail() { //这里是用户拒绝授权后的回调
wx.showModal({
content: '请允许相册权限,拒绝将无法正常使用小程序',
showCancel: false,
success() {
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting["scope.writePhotosAlbum"]) {
} else {
console.log("获取权限失败")
}
}
})
}
})
}
})
} else {
that.startSaveImage();
}
}
})
},
为了方便调用保存相册,单独把保存方法wx.saveImageToPhotosAlbum()封装起来了
// 确认开启相册权限,canvas绘画完成,canvas生成图片完成
startSaveImage() {
let that = this;
wx.saveImageToPhotosAlbum({
filePath: that.data.homePage,
success(res) {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 1500
})
},
fail(err) {
console.log('err', err);
}
});
},
到此全部流程已经结束了,上面圆形头像采用是本地图片,如果是线上还要使用wx.downloadFile()转成本地路径才能使用。
整体代码
wxml
<view class="canvasBox">
<canvas canvas-id='myCanvas' style='width:{{canvasWidth}}px;height:{{canvasHeight}}px;'></canvas>
</view>
<view bindtap="saveHomepage" hover-class="btnHover" class="btn">保存主页</view>
wxss
page {
background-color: antiquewhite;
}
.canvasBox {
display: flex;
justify-content: center;
padding: 20px 0;
}
.btn {
width: 100px;
height: 42px;
background: #FFD401;
border-radius: 22px;
margin: 0 auto;
line-height: 42px;
text-align: center;
}
.btnHover {
opacity: .7;
}
js
Page({
data: {
canvasWidth: 250,
canvasHeight: 250
},
// 获取主页
getCanvasImg(canvasId) {
return new Promise((resolve, reject) => {
let {
canvasWidth,
canvasHeight
} = this.data;
let ctx = wx.createCanvasContext(canvasId);
//给canvas一个白色背景
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fill();
let maskText = '宫崎骏的《龙猫》你看懂了吗?带你寻找隐藏的教育意义!如果你在下雨天的车站,遇到被淋湿的妖怪,请把雨伞借给它,你会得到森林的通行证哦!'; //文字
let fontColor = "#333333"; //字体颜色
let lineHeight = 25; //文字行高
let nameMove = '《龙猫》';
ctx.font = 'normal 16px Arial';
ctx.setFillStyle(fontColor);
// 名字居中显示
ctx.fillText(nameMove, canvasWidth / 2 - ctx.measureText(nameMove).width / 2, 140);
//封装一个函数,ctx:获取的canvas,maskText传的字符串,250:所需要的宽度,2:超出指定行数显示省略号
let showText = this.textSplit(ctx, maskText, 230, 2);
showText.forEach((item,index)=>{
ctx.font = 'normal 14px Arial';
ctx.setFillStyle(fontColor);
ctx.fillText(item,15 , 170 + index*lineHeight);
})
// 头像居中显示
ctx.save();
ctx.beginPath();
ctx.arc(canvasWidth / 2, 65, 40, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage('/image/02.png', 50, 0, 200, 200);
ctx.restore()
ctx.draw(false, () => {
wx.canvasToTempFilePath({
width: canvasWidth,
height: canvasHeight,
canvasId,
success: function (res) {
resolve(res.tempFilePath);
},
fail: function (res) {
reject(res)
}
}, this);
});
})
},
// 保存
saveHomepage(){
let that = this;
//判断当前小程序是否有保存相册的权限
wx.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success(res) {
that.startSaveImage();
},
fail() { //这里是用户拒绝授权后的回调
wx.showModal({
content: '请允许相册权限,拒绝将无法正常使用小程序',
showCancel: false,
success() {
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting["scope.writePhotosAlbum"]) {
} else {
console.log("获取权限失败")
}
}
})
}
})
}
})
} else {
that.startSaveImage();
}
}
})
},
// 确认开启相册权限,canvas绘画完成,canvas生成图片完成
startSaveImage() {
let that = this;
wx.saveImageToPhotosAlbum({
filePath: that.data.homePage,
success(res) {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 1500
})
},
fail(err) {
console.log('err', err);
}
});
},
//根据文字分割
textSplit(ctx, text, lineWidth, lines) {
if (ctx.measureText(text).width < lineWidth) {
return [text]
} else {
let textArr = []; //暂存数组
let c_text = ''; //字符拼接之后的字符串
for (let i = 0; i < text.length; i++) {
if (ctx.measureText(c_text).width < lineWidth) { //字符拼接获取宽度进行判断
c_text += text[i]
} else {
//行数判断
if (textArr.length < lines) {
textArr.push(c_text)
c_text = text[i];
} else if (textArr.length == lines) {
let c_str = textArr[lines - 1];
c_str = c_str.slice(0, c_str.length - 3) + '...'
textArr[lines - 1] = c_str;
return textArr
} else {
return textArr
}
}
};
textArr.push(c_text);
return textArr
}
},
onLoad() {
this.getCanvasImg('myCanvas').then(res=>{
this.setData({
homePage:res
});
});
},
})