html2canvas 1.4.1 在 iOS Safari 中生成图片卡住的问题排查与修复

html2canvas 1.4.1 在 iOS Safari 中生成图片卡住的问题排查与修复

问题现象

在 iOS Safari / 移动端 vConsole 环境中,使用 html2canvas 1.4.1 时无法成功生成图片。

最初看到的报错类似:

text 复制代码
TypeError: undefined is not a function

(near '...t.match(...)...')

同时 html2canvas 日志停在:

text 复制代码
Starting document clone...

之后没有进入 resolved,也没有正常输出 canvas。

最小复现

为了判断是脚本问题还是业务 DOM 问题,先做了一个最小 DOM 测试:

js 复制代码
function testHtml2canvasCore(scriptUrl) {

    scriptUrl = scriptUrl || "https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js";

  


    $.getScript(scriptUrl + "?v=iframefix").done(function () {

        var demo = document.createElement("div");

        demo.id = "html2canvasCoreDemo";

        demo.style.cssText = [

            "position:fixed",

            "left:10px",

            "top:10px",

            "width:120px",

            "height:60px",

            "background:#fff",

            "color:#111",

            "font-size:14px",

            "z-index:999999"

        ].join(";");

        demo.innerHTML = "core demo";

        document.body.appendChild(demo);

  


        html2canvas(demo, {

            scale: 1,

            useCORS: true,

            logging: true

        }).then(function (canvas) {

            console.log("core demo ok", canvas.width, canvas.height);

        }).catch(function (err) {

            console.error("core demo error", err);

        });

    });

}

测试结果:

  • 使用 1.4.1:最小 DOM 也卡住。

这说明问题第一层不在业务 DOM,而在 html2canvas 1.4.1 自身的 document clone / iframe 流程。

根因定位

html2canvas 1.4.1 在生成图片前会 clone 当前 document 到一个隐藏 iframe 中,然后等待 iframe 加载完成。

相关的 minified 代码原本类似:

js 复制代码
In=function(B){

    return new Promise(function(e,A){

        var t=B.contentWindow;

        if(!t)return A("No window assigned for iframe");

        var r=t.document;

        t.onload=B.onload=function(){

            t.onload=B.onload=null;

            var A=setInterval(function(){

                0<r.body.childNodes.length&&"complete"===r.readyState&&(clearInterval(A),e(B))

            },50)

        }

    })

}

关键问题在这里:

js 复制代码
t.onload = B.onload = function () { ... }

原逻辑必须等 iframe 的 load 事件触发后,才开始轮询 iframe document 是否准备好。

在当前 iOS Safari 环境中,这个隐藏 iframe 的 load 事件没有稳定触发,导致 Promise 一直不 resolve,于是 html2canvas 日志停在:

text 复制代码
Starting document clone...

这也是为什么业务 DOM 和极简 DOM 都失败。

修复方案

修复思路是:不要完全依赖 iframe 的 load 事件。注册 onload 的同时,立即启动一次相同的检查逻辑。

补丁后的 In 函数:

js 复制代码
In=function(B){

    return new Promise(function(e,A){

        var t=B.contentWindow;

        if(!t)return A("No window assigned for iframe");

        var r=t.document,n=function(){

            t.onload=B.onload=null;

            var A=setInterval(function(){

                r.body&&0<r.body.childNodes.length&&("complete"===r.readyState||"interactive"===r.readyState)&&(clearInterval(A),e(B))

            },50)

        };

        t.onload=B.onload=n,setTimeout(n,0)

    })

}

相比原逻辑,改动点有三个:

  1. onload 回调提取成 n

  2. 保留原来的 t.onload = B.onload = n

  3. 增加 setTimeout(n, 0),避免 iframe load 事件不触发时永久卡住。

同时轮询条件也做了兼容:

js 复制代码
r.body &&

0 < r.body.childNodes.length &&

("complete" === r.readyState || "interactive" === r.readyState)

这样 iframe document 已经进入 interactive 状态时也可以继续。

验证方式

在移动端 vConsole 中验证最小 DOM:

js 复制代码
testHtml2canvas141()

成功后再验证当前业务 DOM:

js 复制代码
testHtml2canvasCurrentDom()

最终结果:

  • 最小 DOM 可以生成 canvas。

  • 当前业务 DOM 可以继续生成图片。

  • 1.4.1 的样式表现优于旧 plugin 版本。

经验总结

这次问题容易被误判成业务 DOM 或 CSS 问题,因为 html2canvas 的报错栈经过压缩后很难直接读,vConsole 里显示的 t.match 也不一定是根因。

更有效的排查路径是:

  1. 先确认实际加载的是哪一个 html2canvas 文件。

  2. 用极简 DOM 做最小复现。

  3. 如果极简 DOM 也失败,就优先排查 html2canvas 初始化、clone、iframe、资源加载这些基础流程。

  4. 观察 html2canvas 日志停在哪一步。

本次的关键判断点是:极简 DOM 也卡在 Starting document clone...,所以问题不在业务 DOM,而在 1.4.1 的隐藏 iframe clone 等待逻辑。

相关推荐
ZC跨境爬虫5 小时前
跟着 MDN 学CSS day_13 :(深入理解CSS中的元素尺寸调整)
前端·javascript·css·ui·html·tensorflow
threelab6 小时前
Three.js 加载 3D Tiles 瓦片数据 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
百度地图开放平台6 小时前
我用百度地图 Skills 体系重构了物流调度系统,节省了 90% 的人力
前端·github
JavaAgent架构师6 小时前
前端AI工程化(九):AI Agent平台前端架构设计
前端·人工智能
梦想CAD控件7 小时前
网页端对DWG图纸进行预览与批注(CAD轻量化)
java·前端·javascript
不吃土豆的马铃薯7 小时前
Spdlog 进阶:日志基本控制、日志格式控制、异步记录器
linux·服务器·开发语言·前端·c++
wait8 小时前
Vibe Coding 开发技巧
前端·javascript·人工智能
ZengLiangYi8 小时前
Vercel AI SDK 入门:一行代码切换 LLM Provider
前端·javascript·aigc
ZengLiangYi8 小时前
Electron 入门:Web 应用打包成桌面软件
前端·electron