uni-app canvas截图黑屏或空白,主因是dom未就绪、跨层渲染(nvue/webview分离)、原生组件不可捕获;需用onready/$nexttick、native-canvas、uni.takescreenshot等平台适配方案,并注意dpr、权限、滚动状态等细节。

uni-app 里 canvas 截图为什么总黑屏或空白?
常见错误是直接对页面 DOM 节点调用 canvas 绘制,但 uni-app 的渲染层(尤其是 nvue)和 WebView 层分离,document.getElementById 拿不到真实可视区域,或者节点未完成渲染就执行绘制。
- 确保截图逻辑放在
onReady或$nextTick后,等视图真正挂载完毕 - 若用
web-view或原生组件(如map、video),它们无法被canvas捕获,必须换用平台原生能力 - nvue 页面必须用
uni.canvasToTempFilePath配合native-canvas,不能用 web canvas API
示例(App 端有效):
uni.createSelectorQuery()
.select('.screenshot-area')
.boundingClientRect()
.exec(res => {
const { width, height, top, left } = res[0]
// 注意:这里要转成 px 值,nvue 中单位可能是 rpx 或 px,需统一
})
App 和小程序截图用的不是同一套 API
iOS/Android 和微信小程序的截图能力底层完全不同:App 端依赖原生 view 快照(uni.getSubNVueById 或 native-canvas),小程序端靠 canvas + dom-to-image 类库模拟,且受 wxs 限制无法访问所有样式。
- 微信小程序:只能截
view区域,且不能含cover-image、cover-view,否则留白 - App 端(H5 不支持):推荐用
uni.getSubNVueById获取 nvue 实例后调用takeScreenshot方法,精度高、支持透明背景 - H5 端本质是浏览器,只能用
html2canvas,但会丢阴影、filter、transform 等 CSS 效果,且跨域图片会报错
关键区别:
-
uni.canvasToTempFilePath是 canvas 导出,不是屏幕快照 -
uni.takeScreenshot是 App 专属,返回临时文件路径,不经过 canvas
uni.takeScreenshot 在哪些场景下会失败?
这个 API 看似简单,但实际调用失败率高,多数因为上下文不对或权限缺失。
- 必须在 nvue 页面中调用,vue 页面(基于 webview)无效
- 需提前在
pages.json中为对应页面配置"subNVues"或确保当前是 subNVue 实例 - iOS 需在
manifest.json中勾选「iOS 相册权限」,否则保存失败无提示 - 返回的
tempFilePath是本地路径,不能直接用于image标签的src,得用uni.getImageInfo或直接uni.saveImageToPhotosAlbum
常见报错:
-
undefined is not an object (evaluating 'plus.navigator.gallery.save')→ 缺少权限或非 nvue 环境 -
screenshot failed: no view found→ 查询的 subNVue id 不存在或未就绪
截图后图片模糊、尺寸不准、文字锯齿怎么调?
根本原因是像素比(dpr)没对齐。uni-app 默认按逻辑像素渲染,但截图按物理像素采样,导致放大后糊或压缩后失真。
- 截图前先获取设备 dpr:
uni.getSystemInfoSync().pixelRatio - 创建 canvas 时,宽高要乘以 dpr,并设置
style.width/style.height为原始值(保持缩放) - nvue 下更稳妥的方式是用
uni.getSubNVueById(id).takeScreenshot({ quality: 1 }),quality 取值 0.1–1,设为 1 可避免压缩失真 - 文字锯齿多因字体未启用抗锯齿,可在 css 中加
-webkit-font-smoothing: antialiased;(仅 App/H5)
容易被忽略的一点:截图区域如果包含 scroll-view 且处于滚动中,截出来的只是当前可视区,不是整个内容。要截全量,得先 scroll-view 滚到顶部,再延时触发截图。











