uni-app 中 canvas 无法直接截取滚动长页,因 uni.canvasToTempFilePath 仅支持当前 canvas 区域,而滚动内容(如 scroll-view)未渲染进 canvas;可行方案是用原生能力拼接视口截图,推荐使用 uni-plugin-screenshot 插件。

uni-app 里 canvas 无法直接截取滚动长页?原因很实在
uni-app 的 uni.canvasToTempFilePath 只能截当前 canvas 区域,而页面滚动内容(比如 scroll-view 或长 view)根本不在 canvas 里——它压根没被渲染进 canvas 上下文。所以别试「把整个 page 丢进 canvas」,这条路在 H5 和小程序端都走不通,App 端(iOS/Android)也一样。
真正可行的路径只有一条:用原生能力拼接视口截图。uni-app 提供了 uni.createSelectorQuery + boundingClientRect 获取元素尺寸,再配合 uni.getRect(推荐)和多次 uni.pageScrollTo 滚动 + uni.canvasToTempFilePath 截图,最后用原生插件或前端 canvas 合成。
App 端必须用原生插件做长截图?不是必须,但强烈建议
纯 JS 拼接多张截图再合成 canvas,在 App 端容易卡顿、内存爆掉(尤其长页 >10屏),而且 iOS WKWebView 对大 canvas 支持差,常出现空白或黑块。Android 也存在 toDataURL 失败、压缩失真问题。
更稳的方式是调用原生能力:
- 使用已验证的插件,比如
uni-plugin-screenshot(支持 App+小程序,开源且维护活跃) - 或自己封装原生模块:iOS 用
UIGraphicsImageRenderer截整个UIScrollView,Android 用View.draw()+Bitmap合成 - uni-app 官方插件市场搜「长截图」「fullpage screenshot」,认准更新时间在近半年、有 App 平台标注的
如果你坚持不用插件,下面这段 JS 合成逻辑仅作技术参考,不推荐用于生产环境的 App 长截图:
// ⚠️ 仅示意,性能差、兼容风险高
const query = uni.createSelectorQuery().in(this);
query.select('#long-content').boundingClientRect();
query.exec(async (res) => {
const { height, width } = res[0];
const windowHeight = uni.getSystemInfoSync().windowHeight;
const scrollStep = windowHeight * 0.9; // 避免滚动抖动
const parts = [];
<p>for (let top = 0; top setTimeout(r, 16));
uni.pageScrollTo({ scrollTop: top, duration: 0 });
await new Promise(r => setTimeout(r, 100)); // 等渲染</p><pre class="brush:php;toolbar:false;">const temp = await this.captureViewport(); // 自定义截图函数
parts.push(temp);}
// 合成 parts → 大 canvas → toTempFile → 保存 });
uni-plugin-screenshot 在 App 端怎么调用?关键三步
这个插件在 App 端调用的是原生 API,稳定且支持透明背景、指定区域、滚动截全图。安装后注意三点:
- 必须在
manifest.json的「模块权限配置」里勾选「屏幕截图」,否则 Android 会静默失败 - iOS 需在
ios/entitlements.plist添加UIBackgroundModes(仅需后台截屏时),普通场景不用 - 调用前确保目标容器有固定
id,且不能是position: fixed或被transform影响的元素
基础用法示例:
const screenshot = uni.requireNativePlugin('uni-plugin-screenshot');
screenshot.fullScreen({
selector: '#long-content', // 必须是页面内真实存在的 id
quality: 100,
format: 'png'
}, (res) => {
if (res.code === 0) {
uni.saveImageToPhotosAlbum({
filePath: res.data,
success: () => console.log('已保存到相册'),
fail: (e) => console.error('保存失败', e)
});
}
});
为什么 scroll-view 里截图总缺底部?检查这三项
常见现象:滚动到底部后截图,最后一截内容消失、留白、或被遮挡。根本原因不是代码错,而是布局没对齐:
-
scroll-view的height必须是具体数值(如100vh),不能是auto或依赖父容器 flex 布局未设高 - 内部内容需用
padding-bottom补足「滚动惯性」导致的视觉偏移,建议加padding-bottom: 200rpx - 截图前执行
uni.pageScrollTo({scrollTop: 99999})不可靠;应先用uni.createSelectorQuery算出真实高度,再pageScrollTo到height - windowHeight
一个容易忽略的细节:App 端 scroll-view 的 scroll-y 默认为 false,即使写了 style="height: 100vh" 也不生效,必须显式写 scroll-y 属性。











