欢迎光临
我们一直在努力

前端html2canvas使用场景详解

html2canvas 是前端常用的 “DOM 转图片” 库,核心是将页面 DOM 节点渲染为 Canvas,再转为图片(Base64 或 Blob)。以下是 9 种核心使用场景的详细教程,包含代码示例、参数配置、问题解决,覆盖日常开发需求。

一、基础使用:将指定 DOM 转为 Base64 图片

适用于简单场景(如生成证书、截图分享),无需复杂配置。

1. 安装与引入

# npm 安装
npm install html2canvas –save

javascript

// 模块化项目引入(Vue/React/Angular)
import html2canvas from 'html2canvas';

// 非模块化项目(直接引入 CDN)
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>

2. 核心代码

html

<!– 目标 DOM:需要转为图片的容器 –>
<div id="targetDom" style="width: 300px; height: 200px; background: #f5f5f5; padding: 20px;">
<h2>基础截图示例</h2>
<p>这是要转为图片的内容</p>
</div>

<!– 图片预览容器 –>
<img id="previewImg" style="margin-top: 20px; max-width: 100%;" />

javascript

// 触发截图(如点击按钮后)
document.querySelector('#btn').addEventListener('click', async () => {
// 1. 获取目标 DOM
const targetDom = document.getElementById('targetDom');

// 2. 调用 html2canvas 生成 Canvas
const canvas = await html2canvas(targetDom, {
scale: 2, // 2倍缩放,避免图片模糊(关键参数)
useCORS: true, // 允许跨域图片(如网络图片)
logging: false, // 关闭控制台日志
backgroundColor: null // 保留 DOM 原有背景(默认白色)
});

// 3. Canvas 转为 Base64 图片(支持 jpeg/png)
const base64Img = canvas.toDataURL('image/jpeg', 1.0); // 1.0 表示质量(0-1)

// 4. 预览图片
document.getElementById('previewImg').src = base64Img;

// 5. (可选)下载图片
const link = document.createElement('a');
link.href = base64Img;
link.download = '基础截图.jpg';
link.click();
});

二、进阶场景:处理跨域图片

当 DOM 中包含网络图片(如 2026-01-28jjd2ilcunjz.jpg),易出现 “图片空白” 问题,需配置跨域参数。

关键配置

  • 前端配置:useCORS: true + allowTaint: true(允许跨域图片污染 Canvas);
  • 后端配置:图片服务器需返回 Access-Control-Allow-Origin: *(或当前域名),否则跨域图片仍会空白。
  • 完整代码

    javascript

    const canvas = await html2canvas(targetDom, {
    scale: 2,
    useCORS: true, // 允许加载跨域图片
    allowTaint: true, // 允许 Canvas 被跨域图片污染(否则图片会被过滤)
    logging: false,
    // (可选)处理跨域图片加载失败的情况
    onclone: (clonedDoc) => {
    // clonedDoc 是 DOM 克隆体,可在此修改图片地址
    const imgs = clonedDoc.querySelectorAll('img');
    imgs.forEach(img => {
    // 替换图片为同源地址(若后端未配置 CORS 时的备选方案)
    if (img.src.includes('跨域域名')) {
    img.src = img.src.replace('跨域域名', '同源代理域名');
    }
    });
    }
    });

    三、复杂场景:固定宽高 + 滚动内容截图

    适用于 “长列表截图”(如表格、聊天记录),需固定截图宽高,同时包含滚动区域的所有内容。

    核心思路

  • 先保存目标 DOM 的原始样式(overflow/height);
  • 临时修改为 overflow: visible + 自适应高度(确保所有内容展开);
  • 截图完成后恢复原始样式。
  • 完整代码

    javascript

    async function captureScrollContent() {
    const targetDom = document.getElementById('targetDom');
    // 1. 保存原始样式
    const originalStyle = {
    overflow: targetDom.style.overflow,
    height: targetDom.style.height
    };

    try {
    // 2. 临时修改样式:展开所有滚动内容
    targetDom.style.overflow = 'visible';
    targetDom.style.height = 'auto'; // 自适应高度,显示所有内容

    // 3. 截图(固定宽高,避免内容变形)
    const canvas = await html2canvas(targetDom, {
    scale: 2,
    useCORS: true,
    logging: false,
    windowWidth: targetDom.offsetWidth, // 固定截图宽度
    windowHeight: targetDom.offsetHeight // 固定截图高度(此时已包含所有内容)
    });

    // 4. 转为图片并下载
    const base64Img = canvas.toDataURL('image/png', 1.0);
    const link = document.createElement('a');
    link.href = base64Img;
    link.download = '长列表截图.png';
    link.click();

    } finally {
    // 5. 恢复原始样式(无论成功失败都要恢复)
    targetDom.style.overflow = originalStyle.overflow;
    targetDom.style.height = originalStyle.height;
    }
    }

    // 调用
    captureScrollContent();

    四、Vue 项目:组件内 DOM 截图(含响应式数据)

    Vue 中需注意 “DOM 渲染时机”—— 确保数据更新后(如接口请求完成)再截图,避免内容空白。

    核心注意点

  • 用 this.$nextTick() 确保 DOM 已更新;
  • 若用 v-for 渲染列表,需等待列表渲染完成后再截图。
  • 完整代码(Vue 3 示例)

    vue

    <template>
    <div>
    <!– 目标 DOM:包含响应式数据 –>
    <div ref="certDom" class="cert-container">
    <h2>{{ userName }} 的证书</h2>
    <p>项目:{{ projectName }}</p>
    <p>时间:{{ date }}</p>
    </div>

    <button @click="generateCert">生成证书</button>
    <img :src="previewImg" alt="证书预览" style="max-width: 100%; margin-top: 20px;" />
    </div>
    </template>

    <script setup>
    import { ref, nextTick } from 'vue';
    import html2canvas from 'html2canvas';

    // 响应式数据
    const userName = ref('');
    const projectName = ref('');
    const date = ref('2025-01-01');
    const previewImg = ref('');
    const certDom = ref(null); // 目标 DOM 引用

    // 接口请求:获取用户数据
    const fetchUserInfo = async () => {
    const res = await fetch('/api/user');
    const data = await res.json();
    userName.value = data.userName;
    projectName.value = data.projectName;
    };

    // 生成证书(截图)
    const generateCert = async () => {
    // 1. 先获取数据,确保 DOM 已更新
    await fetchUserInfo();
    // 2. 等待 Vue DOM 渲染完成
    await nextTick();

    // 3. 截图(certDom.value 是目标 DOM)
    const canvas = await html2canvas(certDom.value, {
    scale: 2,
    useCORS: true,
    backgroundColor: '#fff'
    });

    // 4. 预览并下载
    previewImg.value = canvas.toDataURL('image/jpeg', 1.0);
    const link = document.createElement('a');
    link.href = previewImg.value;
    link.download = `${userName.value}的证书.jpg`;
    link.click();
    };
    </script>

    <style scoped>
    .cert-container {
    width: 500px;
    height: 700px;
    background: url('@/assets/cert-bg.jpg') no-repeat center;
    background-size: 100% 100%;
    padding: 50px;
    box-sizing: border-box;
    }
    </style>

    五、React 项目:函数组件截图(含 Hooks)

    React 中需用 useRef 获取 DOM 节点,用 useEffect 处理异步渲染时机。

    完整代码(React 18 示例)

    jsx

    import { useRef, useState } from 'react';
    import html2canvas from 'html2canvas';

    const ScreenshotComponent = () => {
    // 1. 获取目标 DOM 引用
    const targetRef = useRef(null);
    // 2. 预览图片状态
    const [previewImg, setPreviewImg] = useState('');

    // 截图函数
    const captureDom = async () => {
    if (!targetRef.current) return;

    // 3. 调用 html2canvas
    const canvas = await html2canvas(targetRef.current, {
    scale: 2,
    useCORS: true,
    logging: false
    });

    // 4. 转为图片
    const base64 = canvas.toDataURL('image/png', 1.0);
    setPreviewImg(base64);

    // 5. 下载图片
    const link = document.createElement('a');
    link.href = base64;
    link.download = 'react截图.png';
    link.click();
    };

    return (
    <div style={{ padding: 20 }}>
    {/* 目标 DOM:用 ref 绑定 */}
    <div
    ref={targetRef}
    style={{ width: 400, height: 300, background: '#e8f4f8', padding: 20 }}
    >
    <h3>React 截图示例</h3>
    <p>当前时间:{new Date().toLocaleString()}</p>
    </div>

    <button onClick={captureDom} style={{ margin: 20 }}>生成截图</button>
    {previewImg && <img src={previewImg} alt="预览" style={{ maxWidth: '100%' }} />}
    </div>
    );
    };

    export default ScreenshotComponent;

    六、特殊场景:隐藏 DOM 截图(不显示在页面)

    适用于 “后台生成图片”(如生成后直接下载,无需在页面显示 DOM),需临时将 DOM 渲染到页面外。

    核心思路

  • 目标 DOM 初始样式设为 position: absolute; left: -9999px; top: -9999px;(隐藏在视口外);
  • 截图完成后可删除该 DOM(可选)。
  • 完整代码

    html

    <!– 隐藏的目标 DOM:在视口外渲染 –>
    <div id="hiddenDom" style="position: absolute; left: -9999px; top: -9999px; width: 500px; height: 300px; background: #fff; padding: 30px;">
    <h2>隐藏 DOM 生成的图片</h2>
    <p>用户:张三</p>
    <p>等级:VIP</p>
    </div>

    <button id="generateBtn">生成隐藏图片</button>

    javascript

    document.getElementById('generateBtn').addEventListener('click', async () => {
    const hiddenDom = document.getElementById('hiddenDom');

    // 截图(与正常 DOM 一致)
    const canvas = await html2canvas(hiddenDom, {
    scale: 2,
    useCORS: true,
    logging: false
    });

    // 下载图片
    const base64 = canvas.toDataURL('image/jpeg', 1.0);
    const link = document.createElement('a');
    link.href = base64;
    link.download = '隐藏DOM图片.jpg';
    link.click();

    // (可选)截图后删除隐藏 DOM
    // hiddenDom.remove();
    });

    七、性能优化:批量截图 + 避免重复渲染

    当需要批量生成图片(如多条数据生成证书),需控制截图顺序,避免同时渲染导致浏览器卡顿。

    核心思路

  • 用 async/await 按顺序截图(一条完成后再截下一条);
  • 截图前判断是否已生成,避免重复操作。
  • 完整代码

    javascript

    // 批量数据(如多条证书信息)
    const certList = [
    { id: 1, userName: '张三', project: '前端开发' },
    { id: 2, userName: '李四', project: '后端开发' },
    { id: 3, userName: '王五', project: 'UI设计' }
    ];

    // 批量截图函数
    async function batchCapture() {
    for (const cert of certList) {
    // 1. 动态创建目标 DOM(每条数据一个 DOM)
    const tempDom = document.createElement('div');
    tempDom.style.width = '500px';
    tempDom.style.height = '700px';
    tempDom.style.background = '#fff';
    tempDom.style.padding = '50px';
    tempDom.style.position = 'absolute';
    tempDom.style.left = '-9999px'; // 隐藏在视口外
    tempDom.innerHTML = `
    <h2>${cert.userName} 的证书</h2>
    <p>项目:${cert.project}</p>
    <p>日期:2025-01-01</p>
    `;
    document.body.appendChild(tempDom);

    try {
    // 2. 截图(按顺序执行)
    const canvas = await html2canvas(tempDom, {
    scale: 2,
    useCORS: true,
    logging: false
    });

    // 3. 下载图片
    const base64 = canvas.toDataURL('image/jpeg', 1.0);
    const link = document.createElement('a');
    link.href = base64;
    link.download = `${cert.userName}的证书.jpg`;
    link.click();

    } finally {
    // 4. 移除临时 DOM(避免内存占用)
    document.body.removeChild(tempDom);
    // (可选)延迟 500ms,避免浏览器卡顿
    await new Promise(resolve => setTimeout(resolve, 500));
    }
    }
    }

    // 调用批量截图
    batchCapture();

    八、问题解决:常见报错与优化方案

    1. 图片模糊

    • 原因:Canvas 默认缩放为 1,屏幕 DPI 过高(如 Retina 屏)导致模糊;
    • 解决:设置 scale: 2 或 scale: window.devicePixelRatio(自适应屏幕 DPI)。

    javascript

    const canvas = await html2canvas(targetDom, {
    scale: window.devicePixelRatio, // 自适应屏幕缩放
    useCORS: true
    });

    2. 跨域图片空白

    • 原因:图片服务器未配置 CORS,或未开启 useCORS: true;
    • 解决:
    • 后端添加 Access-Control-Allow-Origin 响应头;
    • 前端配置 useCORS: true + allowTaint: true;
    • 备选方案:用同源代理服务器转发图片(如 Nginx 代理)。

    3. DOM 内容未完全渲染(如接口数据空白)

    • 原因:截图时机过早,DOM 尚未更新(如接口请求未完成);
    • 解决:
      • Vue:用 this.$nextTick() 等待 DOM 渲染;
      • React:用 useEffect 或 await 等待数据加载;
      • 原生 JS:在接口 then 回调中执行截图。

    4. 大 DOM 截图卡顿

    • 原因:DOM 节点过多(如长列表、复杂表格),渲染耗时;
    • 解决:
    • 简化 DOM(移除截图无关的节点,如隐藏按钮、多余注释);
    • 分批截图(避免一次性渲染大量节点);
    • 关闭日志:logging: false(减少控制台输出耗时)。

    九、高级场景:Canvas 转 Blob 上传服务器

    当需要将生成的图片上传到后端(而非本地下载),需将 Canvas 转为 Blob 格式(比 Base64 更节省带宽)。

    完整代码

    javascript

    async function captureAndUpload() {
    const targetDom = document.getElementById('targetDom');
    const canvas = await html2canvas(targetDom, {
    scale: 2,
    useCORS: true,
    logging: false
    });

    // 1. Canvas 转为 Blob(支持指定格式和质量)
    canvas.toBlob(async (blob) => {
    // 2. 构建 FormData(用于上传)
    const formData = new FormData();
    formData.append('image', blob, '上传图片.jpg'); // 第三个参数是文件名
    formData.append('userId', '123'); // 其他参数(如用户ID)

    // 3. 上传到服务器
    try {
    const res = await fetch('/api/upload-image', {
    method: 'POST',
    body: formData,
    // 注意:FormData 上传无需设置 Content-Type,浏览器会自动处理
    });

    const data = await res.json();
    if (data.success) {
    alert('图片上传成功!');
    console.log('图片地址:', data.imageUrl);
    }
    } catch (err) {
    console.error('上传失败:', err);
    }
    }, 'image/jpeg', 0.8); // 0.8 表示图片质量(0-1,值越高质量越好)
    }

    // 调用
    captureAndUpload();

    赞(0)
    未经允许不得转载:171主机测评 » 前端html2canvas使用场景详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址