
不少做小程序开发的朋友,想在canvas里实现文字绘制,却被各种细节卡住——文字怎么显示?样式咋调整?长文本咋换行?今天咱就把小程序canvas绘文字的门道拆明白,从基础用法到进阶技巧,一步步说清楚。
小程序canvas绘制文字的基础步骤是啥?
想在小程序canvas里画文字,核心是用canvas上下文的绘制方法,先理清楚流程:
创建canvas上下文 → 小程序里用
wx.createCanvasContext(canvasId, this)生成上下文对象(canvasId要和wxml里canvas标签的id对应)。设置文字样式 → 比如字体大小、颜色、对齐方式这些,靠上下文的属性设置,像
ctx.font = '16px 微软雅黑'、ctx.fillStyle = '#333'。执行绘制命令 → 用
fillText(text, x, y)画实心文字,或strokeText(text, x, y)画空心文字(轮廓)。触发渲染 → 最后调用
ctx.draw(),把之前的绘制操作真正渲染到canvas上。
举个简单例子,wxml里放canvas:
<canvas type="2d" id="myCanvas" style="width:300px;height:200px;"></canvas>
js里写绘制逻辑:
Page({
onReady() {
const ctx = wx.createCanvasContext('myCanvas', this)
ctx.font = '20px PingFang SC' // 设置字体
ctx.fillStyle = '#ff0000' // 文字颜色
ctx.fillText('这是测试文字', 50, 100) // 文字内容、x坐标、y坐标
ctx.draw() // 渲染
}
})这样就能在canvas里看到红色的“这是测试文字”了。draw() 是异步的,要是后续还有绘制操作,得考虑用 draw(false, callback) 来叠加绘制,避免覆盖之前内容。
怎么给绘制的文字调样式?(字体、颜色、对齐方式)
基础绘制只能满足“有文字”,实际需求里得让文字好看、位置对,这就得调样式细节:
字体样式:font属性
和CSS的font语法差不多,要把字号、字体族等信息拼一起。ctx.font = 'bold 18px 宋体' ,顺序是「样式(可选,如bold/italic) 字号 字体名称」,注意小程序里要确保字体在手机里支持,优先用系统默认字体(像PingFang SC、HarmonyOS Sans),避免因字体缺失显示异常。
文字颜色:fillStyle / strokeStyle
实心文字用 fillStyle ,空心轮廓用 strokeStyle ,值可以是纯色(如 #ff0000 )、渐变(后面讲特殊技巧)、图案,比如想让文字描边是蓝色,就写 ctx.strokeStyle = 'blue' ,再调 lineWidth 控制描边粗细,最后用 strokeText 绘制。
对齐方式:textAlign + textBaseline
这俩属性决定文字在(x,y) 坐标处的对齐规则:
textAlign控制水平对齐,可选值start(默认,按文字开始方向对齐,比如中文从左到右,x是文字左边缘)、center(x是文字中心)、end(x是文字右边缘)、left(同start)、right(同end)。textBaseline控制垂直对齐,可选值top(y是文字顶部)、hanging(悬挂基线,适合某些特殊字体)、middle(y是文字中间)、alphabetic(默认,字母基线,中文也基于这个)、ideographic(表意文字基线,底部对齐)、bottom(y是文字底部)。
举个对齐的例子:想让文字在canvas水平居中、垂直居中,假设canvas宽300,高200,那x设150,y设100,
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText('居中文字', 150, 100)这样文字就稳稳待在canvas正中间了,不用自己算偏移量。
长文本自动换行咋实现?
小程序canvas的 fillText 默认只画一行,要是文字太长(比如一段介绍文案),就得自己拆分换行,核心思路是:把长字符串按每行能容纳的宽度分割,循环绘制每行。
具体步骤:
测量文字宽度 → 用
ctx.measureText(text).width能拿到指定样式下文字的宽度。分割文本 → 从第一个字符开始,逐个累加,直到累加宽度超过canvas可用宽度,就把前面的作为一行,剩下的继续处理。
循环绘制每行 → 每行的
y坐标递增(比如每行间隔24px),依次绘制。
代码示例(假设canvas宽度300,行高24px):
function drawMultiLineText(ctx, text, x, y, maxWidth, lineHeight) {
let currentLine = '' // 当前行内容
let words = text.split('') // 按字符拆分(如果是英文可按空格拆单词)
for (let word of words) {
let testLine = currentLine + word
let testWidth = ctx.measureText(testLine).width
if (testWidth > maxWidth && currentLine) { // 超过宽度且当前行有内容
ctx.fillText(currentLine, x, y)
currentLine = word
y += lineHeight
} else {
currentLine = testLine
}
}
// 处理最后一行
if (currentLine) {
ctx.fillText(currentLine, x, y)
}
}
// 调用时:
const ctx = wx.createCanvasContext('myCanvas', this)
ctx.font = '16px PingFang SC'
drawMultiLineText(ctx, '这里是一段很长很长的测试文字,需要自动换行显示...', 20, 30, 260, 24)
ctx.draw()这里要注意:如果是中英文混合,按字符拆分更稳妥;如果是纯英文,按空格拆单词体验更好(避免单词被截断)。measureText 依赖当前的font样式,所以拆分前要确保已经设置好字体,不然测量宽度会不准。
文字绘制时的性能坑怎么避?
要是做海报生成、动态图表这类文字多的场景,canvas绘制容易卡,得注意性能优化:
减少draw()调用次数
ctx.draw() 是把绘制命令批量渲染,频繁调用会触发多次重绘,所以尽量把所有绘制操作(文字、图形等)放在一次draw里,比如先把所有文字样式设置、位置计算好,再统一调draw,而不是画一行文字就draw一次。
缓存measureText结果
每次 measureText 都会触发内部计算,文字多的时候很耗性能,如果是固定样式的文字(比如标题、固定文案),可以把测量好的宽度存在变量里,避免重复测量。
用离屏canvas预处理(小程序2d canvas支持)
如果需要绘制复杂重复的文字元素(比如带样式的标签重复出现),可以先在离屏canvas里画好,再把离屏canvas当作图片画到主canvas上,不过小程序里离屏canvas的创建和使用要注意兼容,得先看基础库版本。
避免不必要的样式重设
比如循环绘制多行文字时,字体、颜色这些样式如果没变化,就别在循环里重复设置,把样式设置提到循环外面,减少上下文状态切换的开销。
优化示例:
Page({
onReady() {
const ctx = wx.createCanvasContext('myCanvas', this)
// 统一设置样式
ctx.font = '16px PingFang SC'
ctx.fillStyle = '#333'
ctx.textAlign = 'left'
// 批量绘制内容
drawMultiLineText(ctx, '长文本...', 20, 30, 260, 24)
ctx.fillText('单独一行的标题', 20, 200)
// 最后一次draw
ctx.draw()
}
})这样所有绘制操作一次性渲染,比多次draw流畅很多。
有没有特殊场景的文字绘制技巧?(比如渐变文字、阴影文字)
普通文字满足不了设计需求时,这些技巧能让文字更炫酷:
渐变文字
思路是用线性渐变/径向渐变作为fillStyle,再绘制文字,步骤:
创建渐变对象:
const gradient = ctx.createLinearGradient(x0, y0, x1, y1)(线性渐变,四个参数是渐变起始和结束的坐标)。添加颜色节点:
gradient.addColorStop(0, '#ff0000')、gradient.addColorStop(1, '#00ff00')(0到1是渐变范围)。把渐变设为
fillStyle:ctx.fillStyle = gradient。绘制文字:
ctx.fillText('渐变文字', 50, 100)。
代码示例(水平渐变文字):
const ctx = wx.createCanvasContext('myCanvas', this)
const gradient = ctx.createLinearGradient(0, 0, 200, 0)
gradient.addColorStop(0, 'red')
gradient.addColorStop(1, 'blue')
ctx.font = '30px 黑体'
ctx.fillStyle = gradient
ctx.fillText('渐变文字', 50, 100)
ctx.draw()这样文字就会从红色渐变到蓝色,视觉效果拉满。
阴影文字
给文字加阴影,能让文字更立体,靠这几个属性:
shadowOffsetX:阴影水平偏移量(正负控制方向)。shadowOffsetY:阴影垂直偏移量。shadowBlur:阴影模糊程度(数值越大越模糊)。shadowColor:阴影颜色(要带透明度的话用rgba)。
代码示例:
ctx.font = '24px 华文楷体'
ctx.shadowOffsetX = 2
ctx.shadowOffsetY = 2
ctx.shadowBlur = 4
ctx.shadowColor = 'rgba(0,0,0,0.3)'
ctx.fillText('带阴影的文字', 80, 120)
ctx.draw()这样文字下方会有淡淡的阴影,质感瞬间提升,要注意,阴影是叠加在文字上的,如果多个文字元素都要阴影,要确保样式设置的范围,避免互相干扰。
常见错误排查:文字不显示、样式不对咋解决?
开发时遇到文字没出现、样式乱套,大概率是这些原因:
文字不显示
没调
ctx.draw():所有绘制操作后必须调draw才会渲染,漏了就看不到。canvas尺寸不对:wxml里canvas的
style宽度高度和实际绘制时的逻辑尺寸不一致,导致文字画到 canvas 外面,要确保style的宽高和canvas的实际像素尺寸匹配(小程序canvas默认是300x150,样式里要显式设置)。文字颜色和背景色一样:比如canvas背景是白色,文字
fillStyle也设成白色,自然看不到,检查颜色值是否正确。
字体样式不生效
font属性格式错:必须包含字号和字体族,比如写成ctx.font = '微软雅黑'(没写字号)就无效,得是'16px 微软雅黑'。字体不存在:手机里没装设置的字体(华文楷体”在部分安卓机可能没有),换成系统默认字体(如
PingFang SC)试试。
对齐方式错乱
textAlign/textBaseline理解错:比如想让文字右对齐,设了textAlign: 'right',但x坐标给的是canvas最左端,结果文字被画到canvas外面,要记住,textAlign是基于x坐标的对齐方式,右对齐时x应该是文字右边缘的位置。没在绘制前设置对齐属性:样式设置要在
fillText/strokeText之前,不然不生效。
长文本换行失败
measureText没拿到正确宽度:因为设置font在measureText之后,导致测量的是默认字体的宽度,要确保measureText前已经设置好font。拆分逻辑有漏洞:比如中英文混合时按单词拆分(用
split(' ')),但中文没空格,导致整段文字被当成一个单词,无法拆分,这种情况要换成按字符拆分。
遇到问题时,先把canvas背景设成浅色(比如浅黄色),方便看文字位置;再逐一检查绘制步骤、样式设置、坐标计算,一般能定位到问题。
小程序canvas绘制文字,看着是个小功能,实际要考虑样式、排版、性能、特殊效果等方方面面,从基础的`fillText`调用,到样式微调、长文本换行,再到渐变阴影这类特效,每一步都得结合场景去试,多写demo,遇到问题拆分成“样式设置→坐标计算→绘制命令→渲染触发”这几个环节排查,基本都能解决,要是做海报生成、数据可视化这类重canvas的需求,把文字绘制的细节吃透,能少走很多弯路~








网友评论文明上网理性发言 已有0人参与
发表评论: