游乐游手机版
首页/前端开发/文章详情

uni-app解决小程序Canvas在iOS端模糊Bug

时间:2026-07-20 06:49
iOS真机Canvas模糊因pixelRatio为3时未适配物理像素。需设置canvas width height为逻辑尺寸乘dpr,调用ctx scale(dpr,dpr),固定CSS尺寸。获取节点用createSelectorQuery异步查询,图片先下载再绘制,重绘前重新scale。

iOS真机上的Canvas发虚,核心原因其实很简单:pixelRatio为3的时候,没有正确适配物理像素。解决方案也直白——必须同时设置canvas.width/height为逻辑尺寸乘以dpr,然后调用ctx.scale(dpr, dpr),再配合CSS固定显示尺寸。三个步骤,缺一不可。

uni-app如何解决小程序端Canvas绘制在iOS端显示模糊Bug

为什么iOS真机上Canvas总是发虚,而开发者工具不报错?

因为微信小程序在iOS端的Canvas渲染管线对dpr更敏感,且不自动做像素对齐。开发者工具用的是Mac桌面WebView模拟,pixelRatio固定为1或2,但真实iPhone——尤其是12/13/14系列——pixelRatio直接跳到3。如果canvas还按375×667逻辑尺寸初始化,那它就不是“画得糊”,而是“画得少,再被硬生生撑大”。

必须同时改 canvas.width/height 和 ctx.scale(),缺一不可

注意,这里必须同时改canvas.width/height和ctx.scale(),缺一不可。只调scale不行,只改CSS宽高也不行。关键点在于:canvas元素的width和height属性决定绘图缓冲区物理像素数,CSS控制显示大小,两者必须按比例匹配。

  • canvas.width = 375 * dpr,canvas.height = 667 * dpr(以设计稿375px宽为例)
  • 紧接着调用ctx.scale(dpr, dpr),让后续所有坐标、字号、线宽都按逻辑尺寸写,比如fillText('hello', 20, 30)不用再乘dpr
  • 最后,Canvas组件的:style里仍设width: '375px'; height: '667px',保持布局不变

onReady里拿不到canvas节点?用createSelectorQuery异步查

uni-app中this.$refs.canvas在iOS真机上常为null,尤其配合v-if或条件渲染时。必须用uni.createSelectorQuery()主动查询,且要等exec回调返回node才安全。这里有几个关键点:

  • 别在mounted里直接uni.createCanvasContext,此时DOM还没就绪
  • 正确时机是onReady钩子 + createSelectorQuery().select('#myCanvas').fields({ node: true }).exec()
  • 拿到res[0].node后,再调node.getContext('2d')(注意:uni-app里推荐用uni.createCanvasContext,但需传入该node)

drawImage加载图片仍模糊?先下载再绘,绕过跨域和降采样

iOS WebView对远程drawImage('https://...')有双重限制:一是CORS拦截导致空白,二是自动降采样(尤其带orientation的JPEG),哪怕原图是@3x也会被压成模糊块。解决方案是:

  • 必须走uni.downloadFile → uni.getImageInfo → ctx.drawImage三步链
  • getImageInfo返回的width/height是原始物理像素,绘图时要除以dpr换算成逻辑尺寸,否则会超框
  • 如果水印文字仍毛边,加一句ctx.imageSmoothingEnabled = false关掉插值,细线和小字立刻锐利

最易被忽略的一点是:每次重绘前都要重新scale,不能只在初始化时调一次。另外,canvas.width/height设完后,务必确认它没被其他样式或父容器约束覆盖——iOS对flex容器里的canvas尺寸计算特别脆弱,这一点必须警惕。

来源:https://www.php.cn/faq/2812791.html
上一篇敏捷开发流中HTML代码质量纳入Sprint验收标准 下一篇HTML表格border-collapse消除单元格间隙方法
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
CSS星空背景遮挡页面链接的有效修复方法
前端开发 · 2026-07-21

CSS星空背景遮挡页面链接的有效修复方法

CSS星空背景元素因绝对定位与高z-index覆盖视口,导致底层链接的鼠标事件被屏蔽。为纯装饰层添加`pointer-events:none`属性,可透传鼠标事件,恢复链接交互,且不影响动画渲染与性能表现。这样既保留视觉装饰,又确保用户正常点击底层链接。

组合键Ctrl+C触发不同音符的播放方法
前端开发 · 2026-07-21

组合键Ctrl+C触发不同音符的播放方法

通过监听键盘事件并检测修饰键状态,实现同一字母键在不同组合下播放不同音符。需注意使用event ctrlKey正确拼写,调用preventDefault阻止默认行为,统一转小写,并考虑重复触发过滤。可扩展的键映射方案便于维护。

Vue与Three.js实现人物奔跑3D场景
前端开发 · 2026-07-21

Vue与Three.js实现人物奔跑3D场景

基于Vue与Three js构建人物奔跑场景:人物加载GLTF骨骼动画原地循环跑步,巨型草坪平面持续向后平移,营造无限奔跑错觉,并添加线性白雾增强空间层次,代码工程化实现。

CSS :has()父选择器根据图片是否存在调整文字宽度
前端开发 · 2026-07-21

CSS :has()父选择器根据图片是否存在调整文字宽度

聊聊` card:has(img)`和` card:not(:has(img))`的真实用法 这两个组合是目前最稳定、纯粹基于DOM结构进行判断的方案。适用场景非常明确: * ` card:has(img) text`:当卡片里有``标签时,文字容器收窄,比如设为`width: 70%`,

正确使用回调函数实现链式调用多个函数
前端开发 · 2026-07-21

正确使用回调函数实现链式调用多个函数

本文深入解析回调函数链式调用的常见误区和正确用法,通过修复 a → b → c 顺序执行失败的典型问题,阐明回调传递的核心本质:传递函数引用而非调用结果,并提供可运行的代码示例与关键注意事项,帮助开发者彻底掌握回调函数链式调用写法。 在实际项目开发中,利用回调函数实现 a → b → c 这样的顺序