步骤 1:在页面中添加画布组件
首先在 .wxml 中定义画布,注意设置固定宽高(生成图片时尺寸更可控),并添加一个生成按钮:
<!-- pages/card/card.wxml -->
<view class="container">
<!-- 画布:用于绘制名片 -->
<canvas
type="2d"
canvas-id="cardCanvas"
width="600"
height="400"
class="canvas"
></canvas>
<!-- 生成图片按钮 -->
<button bindtap="generateCard" class="generate-btn">生成名片图片</button>
<!-- 预览生成的图片 -->
<image
src="{{cardImage}}"
mode="widthFix"
class="preview-img"
wx:if="{{cardImage}}"
></image>
</view>
步骤 2:样式设置(可选)
在 .wxss 中设置画布和按钮的样式,确保画布显示正常:
/* pages/card/card.wxss */
.container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx;
}
.canvas {
border: 1px solid #eee;
width: 600rpx; /* 小程序中rpx适配,600rpx约等于300px */
height: 400rpx;
}
.generate-btn {
margin-top: 30rpx;
background: #07c160;
color: white;
}
.preview-img {
margin-top: 30rpx;
width: 600rpx;
border: 1px solid #eee;
}
步骤 3:使用 Canvas 2D API 绘制名片
在 .js 中获取画布上下文,通过 API 绘制名片元素(背景、头像、文字、二维码等):
// pages/card/card.js
Page({
data: {
cardImage: '', // 生成的名片图片路径
},
onLoad() {
// 页面加载时先绘制名片
this.drawCard();
},
// 绘制名片
drawCard() {
// 获取画布上下文(2D模式)
const query = wx.createSelectorQuery()
query.select('#cardCanvas')
.fields({ node: true, size: true })
.exec((res) => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
// 设置画布实际尺寸(与wxml中width/height一致)
const dpr = wx.getSystemInfoSync().pixelRatio // 设备像素比,避免模糊
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr) // 缩放上下文,解决高清屏模糊问题
// 1. 绘制名片背景(渐变效果)
const gradient = ctx.createLinearGradient(0, 0, 600, 0)
gradient.addColorStop(0, '#f5f5f5')
gradient.addColorStop(1, '#e8f5e9')
ctx.fillStyle = gradient
ctx.fillRect(0, 0, 600, 400) // 绘制矩形背景
// 2. 绘制头像(先加载图片再绘制)
const avatarImg = canvas.createImage()
avatarImg.src = '/images/avatar.jpg' // 本地头像路径(需提前放置)
avatarImg.onload = () => {
// 绘制圆形头像(先画圆再裁剪)
ctx.save()
ctx.beginPath()
ctx.arc(100, 100, 60, 0, 2 * Math.PI) // 圆心(100,100),半径60
ctx.clip() // 裁剪为圆形
ctx.drawImage(avatarImg, 40, 40, 120, 120) // 绘制图片(填满圆形区域)
ctx.restore() // 恢复上下文状态
// 3. 绘制姓名
ctx.font = 'bold 36px sans-serif'
ctx.fillStyle = '#333'
ctx.fillText('张三', 220, 100)
// 4. 绘制职位
ctx.font = '24px sans-serif'
ctx.fillStyle = '#666'
ctx.fillText('产品经理', 220, 140)
// 5. 绘制联系方式(电话/微信)
ctx.font = '20px sans-serif'
ctx.fillStyle = '#666'
ctx.fillText('电话:13800138000', 220, 180)
ctx.fillText('微信:zhangsan123', 220, 220)
// 6. 绘制公司logo(可选)
const logoImg = canvas.createImage()
logoImg.src = '/images/logo.png' // 本地logo路径
logoImg.onload = () => {
ctx.drawImage(logoImg, 450, 60, 80, 80) // 绘制到右上角
}
// 7. 绘制二维码(可选,需提前准备二维码图片)
const qrImg = canvas.createImage()
qrImg.src = '/images/qrcode.jpg' // 本地二维码路径
qrImg.onload = () => {
ctx.drawImage(qrImg, 450, 220, 100, 100) // 绘制到右下角
}
// 8. 绘制底部线条
ctx.strokeStyle = '#ddd'
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(50, 350)
ctx.lineTo(550, 350)
ctx.stroke()
// 9. 绘制公司名称
ctx.font = '22px sans-serif'
ctx.fillStyle = '#999'
ctx.fillText('XX科技有限公司 © 2023', 180, 380)
}
})
},
// 生成名片图片(保存到本地或展示)
generateCard() {
wx.canvasToTempFilePath({
canvasId: 'cardCanvas',
success: (res) => {
this.setData({
cardImage: res.tempFilePath // 展示生成的图片
})
// 可选:保存到相册
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => wx.showToast({ title: '保存成功' }),
fail: (err) => console.error('保存失败', err)
})
},
fail: (err) => console.error('生成图片失败', err)
})
}
})
关键说明:
-
画布尺寸与模糊问题 :通过
pixelRatio缩放画布,解决高清屏幕下绘制内容模糊的问题(核心是canvas.width = 实际宽 * dpr并ctx.scale(dpr, dpr))。 -
图片加载 :绘制网络图片或本地图片时,必须在
onload回调中执行绘制(确保图片加载完成),否则会绘制失败。 -
元素绘制顺序:先绘制底层元素(如背景),再绘制上层元素(如文字、头像),避免被覆盖。
-
生成图片 :使用
wx.canvasToTempFilePath将画布内容转为临时图片路径,可用于展示或保存到相册(需用户授权)。