uni-app实现图片镜像翻转必须用canvas绘制,不能依赖css transform;需在onready中调用uni.createcanvascontext('mycanvas', this)绑定上下文,再通过ctx.translate与ctx.scale组合实现水平或垂直翻转,并确保ctx.draw(true, callback)完成后再调用canvastotempfilepath导出。

uni-app 实现图片镜像翻转,必须用 canvas 绘制,不能靠 CSS 的 transform: scaleX(-1) —— 因为后者只改显示,导出或上传时仍是原方向。
镜像翻转前必须先获取 canvas 上下文且绑定 this
常见错误是把 uni.createCanvasContext 放在 onLoad 或方法里直接调用,结果上下文没绑定组件实例,绘图失败。
-
uni.createCanvasContext('myCanvas', this)第二个参数this不可省略,否则ctx无法访问组件 data 和生命周期 - 必须在
onReady中初始化:onReady() { this.ctx = uni.createCanvasContext('myCanvas', this) } - 后续所有
ctx.drawImage、ctx.scale操作都依赖这个已绑定的ctx
水平/垂直镜像:用 ctx.scale(-1, 1) 或 ctx.scale(1, -1)
直接调 ctx.scale(-1, 1) 会让坐标系翻转,但图像会画到画布外(负坐标区域),必须配合 ctx.translate 把原点移到右侧或底部。
- 水平镜像(左右翻):
ctx.translate(canvasWidth, 0) ctx.scale(-1, 1)
- 垂直镜像(上下翻):
ctx.translate(0, canvasHeight) ctx.scale(1, -1)
- 注意:
canvasWidth和canvasHeight必须是整数,且等于目标图片原始宽高(比如图片 600×400,canvas 的width和height属性也得设为600和400) - 别用 CSS 的
style.width/style.height控制缩放,那只是显示比例,不影响实际绘制像素范围
base64 图片加载时机错乱导致绘图为空
用 new Image() 加载 base64 字符串时,onload 可能同步触发(尤其缓存命中),而此时 this.ctx 还没创建好,绘图就静默失败。
- 正确做法:设标志位,分离加载与绘制逻辑
this.img = new Image() this.img.onload = () => { this.imgReady = true; this.tryDraw() } this.img.src = 'data:image/png;base64,...' -
tryDraw()中判断:if (this.ctx && this.imgReady) { this.ctx.drawImage(this.img, 0, 0) this.ctx.draw() } - 高清 base64 图(宽高 >1000px)容易触发内存警告,建议提前压缩或限制最大尺寸
导出镜像后图片仍是原方向?检查 canvasToTempFilePath 调用时机
真机上常出现「明明画了镜像,保存出来却是正的」——根本原因是没等 ctx.draw() 完成就调了保存 API。
- 必须传入
draw的回调:this.ctx.draw(true, () => { uni.canvasToTempFilePath({ canvasId: 'myCanvas', success: (res) => { /* res.tempFilePath 即镜像图 */ } }) }) - H5 和小程序平台的
uni.canvasToTempFilePath行为一致,但 App 端(iOS/Android)需确认是否支持该 API;若不支持,需 fallback 到canvas.toDataURL(H5)或原生插件 - iOS 上 canvas 宽高为 0 或未设 style 尺寸,会导致保存白图,务必检查
<canvas></canvas>的width、height和:style是否匹配
镜像本身很简单,真正卡住人的永远是上下文绑定、异步时机、像素尺寸对齐这三处。尤其是 this.ctx 初始化位置和 ctx.draw() 的回调使用,漏掉任何一个,图就“画了但没画”。











