uni-app局部截图需用canvas重绘目标区域,非H5平台不可用DOM截图;微信小程序必须声明type="2d" canvas并确保onReady后绘制;黑图主因是绘制未完成或canvas尺寸为0;App端建议优先使用原生插件。

uni-app 里用 canvas 截局部区域,不是靠截图 API
uni-app 没有直接的「页面某块 DOM 截图」能力,uni.canvasToTempFilePath 只能从 canvas 上取图,所以得先把目标区域内容「画进 canvas」。常见错误是试图用 uni.createSelectorQuery 拿到元素位置后直接截屏——这在非 H5 平台(如微信小程序、App)根本行不通,因为原生渲染层不暴露像素数据。
实操建议:
- 用
uni.createSelectorQuery()获取目标区域的left、top、width、height,但仅作定位参考 - 把要截图的内容(比如一个
<view class="target-area"></view>)提前用纯 canvas 绘制逻辑重绘一遍,或改用 canvas + 自绘组件(如图表、签名板) - H5 平台可走
html2canvas,但注意它不兼容小程序和 App,且对 transform、filter、跨域图片支持差
微信小程序里 canvas 局部导出必须用 type="2d" 或 type="webgl"
老式 canvas(type="2d" 缺失时默认的旧版)在微信小程序中无法正确调用 uni.canvasToTempFilePath,会报错 canvas is not defined 或导出黑图。这是真坑,文档没强调,但实测 90% 的局部截图失败都卡在这。
实操建议:
- WXML 中声明 canvas 必须带
type="2d":<canvas canvas-id="myCanvas" type="2d"></canvas> - JS 中创建上下文要用
uni.createCanvasContext('myCanvas', this),且确保组件已挂载(onReady后再查 canvas 尺寸) - 若需高清图,记得设置
scale:在canvasToTempFilePath的 options 里加quality: 1和适配 dpr 的宽高(例如设备像素比 3,canvas 宽高设为实际区域 ×3)
uni.canvasToTempFilePath 导出黑图的三个高频原因
不是代码写错了,而是环境或时机不对。黑图基本等于 canvas 没画进去东西,或者画了但没等渲染完成就导出了。
实操建议:
- 确保绘制操作全部放在
ctx.draw(true, callback)的回调里执行导出,不能画完就立刻调canvasToTempFilePath - 检查 canvas 宽高是否为 0:用
uni.createSelectorQuery().select('#myCanvas').boundingClientRect()确认尺寸已计算 - 避免在
v-if切换后立即截图:DOM 还没渲染,canvas 就空着。改用$nextTick或延时 100ms
App 端(iOS/Android)局部截图要绕开 WebView 渲染限制
App 端本质是用 WebView 渲染,canvas 绘制受系统 WebKit 引擎限制,尤其是 iOS 15+ 对离屏 canvas 支持不稳定,容易白屏或黑图。这时候不能硬刚 canvas,得换思路。
实操建议:
- 优先用
nativePlugins:比如插件市场里的screen-shot或自研原生模块,传入 view 的 native id(通过uni.requireNativePlugin调用) - 若必须 web 方案,把局部内容转成 SVG 字符串,再用
plus.nativeObj.View加载 SVG 并截图(仅 Android 支持较好) - 别依赖
document.getElementById:App 端 Vue 渲染后 DOM 结构和调试器看到的不一致,selector query 更可靠
真正麻烦的是跨平台一致性——H5 用 html2canvas,小程序用 type="2d" canvas,App 最好走原生。一个功能三套实现,不是写法多难,而是边界 case 太多:字体没加载完、异步图片未 decode、canvas 被其他动画覆盖……这些细节一漏,就是用户反馈“有时候能截,有时候黑”。

















