You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移动端Html2Canvas无法正常工作的问题求助

移动端PDF生成失败问题解决方案

问题根源

  1. 固定延迟不可靠:移动端设备性能差异大,500ms延迟无法保证所有设备完成页面重绘(viewport修改、元素隐藏后的渲染),导致html2canvas捕获时机过早。
  2. 多层嵌套setTimeout:异步逻辑混乱,不仅难以维护,还可能因浏览器事件循环优先级问题导致捕获失败。
  3. html2canvas参数缺失:未配置适配移动端的渲染参数,加重设备负载,导致捕获中断。

解决方案代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>

<script>
document.getElementById('generate-pdf').addEventListener('click', async function() {
  const isMobile = screen.width < 1024;
  let originalViewportContent = null;
  const content = document.getElementById('pdf-content');
  const elementsToExclude = content.querySelectorAll('.exclude');
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF('p', 'pt', 'a4');

  // --- 页面预处理 ---
  try {
    // 隐藏需要排除的元素
    elementsToExclude.forEach(el => el.style.display = 'none');
    
    // 移动端修改viewport并等待重绘
    if (isMobile) {
      const viewportMeta = document.querySelector('meta[name="viewport"]');
      originalViewportContent = viewportMeta.getAttribute('content');
      viewportMeta.setAttribute('content', 'width=800');
      // 等待浏览器完成两次重绘,确保布局稳定
      await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
      console.log("Viewport已临时设置为width=800,页面重绘完成");
    }

    console.log("开始PDF生成流程");

    // --- html2canvas捕获配置 ---
    const canvas = await html2canvas(content, {
      scale: isMobile ? 1 : 2, // 移动端降低缩放比减少负载
      useCORS: true, // 处理跨域图片
      logging: false, // 关闭内部日志减少性能消耗
      backgroundColor: '#ffffff', // 确保背景色正确渲染
      timeout: 10000 // 设置超时,避免无限等待
    });
    console.log("Canvas捕获完成");

    // --- PDF生成 ---
    const imgFormat = isMobile ? 'image/jpeg' : 'image/png';
    const imgData = canvas.toDataURL(imgFormat, isMobile ? 0.8 : 1.0); // 移动端JPEG压缩质量设为0.8进一步降负载
    
    const imgWidth = canvas.width;
    const imgHeight = canvas.height;
    const pageWidth = 595.28;
    const pageHeight = 841.89;
    
    const scaleX = pageWidth / imgWidth;
    const scaleY = pageHeight / imgHeight;
    const finalScale = Math.min(scaleX, scaleY);
    const xOffset = (pageWidth - imgWidth * finalScale) / 2;
    const yOffset = (pageHeight - imgHeight * finalScale) / 2;

    doc.addImage(imgData, imgFormat.toUpperCase(), xOffset, yOffset, imgWidth * finalScale, imgHeight * finalScale, undefined, 'FAST');
    console.log("图片已添加到PDF");

    // 生成文件名
    const companyName = document.querySelector('.company-name')?.innerText.trim() || '';
    const fileName = companyName ? `${companyName} Contract.pdf` : 'Contract.pdf';
    
    doc.save(fileName);
    console.log(`PDF已保存:${fileName}`);

  } catch (error) {
    console.error('PDF生成失败:', error);
  } finally {
    // --- 恢复页面状态 ---
    elementsToExclude.forEach(el => el.style.display = '');
    console.log("已恢复排除元素的可见性");

    if (isMobile && originalViewportContent) {
      const viewportMeta = document.querySelector('meta[name="viewport"]');
      if (viewportMeta) {
        viewportMeta.setAttribute('content', originalViewportContent);
        console.log("已恢复原始Viewport设置");
      }
    }
  }
});
</script>

关键改动说明

  • 用async/await替代嵌套setTimeout:异步逻辑更清晰,确保操作顺序,避免回调地狱。
  • requestAnimationFrame等待重绘:修改viewport和隐藏元素后,等待浏览器完成两次重绘,确保布局稳定后再执行捕获,替代不可靠的固定延迟。
  • 优化html2canvas参数:添加timeout避免无限等待,useCORS处理跨域图片,移动端降低JPEG压缩质量进一步减少负载。
  • 统一finally块恢复页面状态:无论成功还是失败,都能确保页面元素和viewport恢复原样,避免影响用户后续操作。
  • 可选链处理companyName:避免因元素不存在导致的报错。

内容的提问来源于stack exchange,提问作者Marioko53

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:29:59