纯前端如何实现批量dom转图片,并下载成压缩包

简介: 【8月更文挑战第22天】纯前端如何实现批量dom转图片,并下载成压缩包

需求背景

这几天捣鼓一些小东西,需要实现这样一个功能,将页面指定的dom批量下载成压缩包。功能大致如下:
将每条评论信息转成图片,然后放到一个压缩包里下载下来。233.gif
压缩包内容
image.png
这篇文章就简单介绍下,我是如何实现的。

技术思路

要将dom转成图片,我们直接使用html2canvas就可以;要将所有图片放到压缩包里,我们首先获取到每个图片的
base64Data编码信息,最后借助jszip就可以实现。

技术方案

这篇文章就不适用vue了,用react写demo吧,函数是一样的。最后我会放上vue版本的完整代码。

使用云编译器进行调试

以下demo,大家可以直接在豆包云vscode编译器中调试,云编译器免配置任何环境,可以直接使用。

必要依赖安装

npm i file-saver
npm i html2canvas
npm i jszip

这三个包分别提供了在浏览器端实现文件保存、网页截图和 ZIP 文件处理的功能。

基础代码框架搭建

import {
   
    useRef, useState } from "react";
import html2canvas from "html2canvas";
import JSZip from "jszip";
import FileSaver from "file-saver";
function App() {
   
   
  // 绑定dom 和vue的ref一样
  const commentRefs = useRef([]);

  // 图片导出
  const exportImages = async () => {
   
   };

  const mockData = [
    {
   
    name: "张三", age: 18 },
    {
   
    name: "李四", age: 18 },
    {
   
    name: "王五", age: 18 },
    {
   
    name: "石小石", age: 18 },
  ];
  return (
    <>
      <div>
        {
   
   mockData.map((item, index) => (
          <div key={
   
   index} ref={
   
   (el) => (commentRefs.current[index] = el)}>
            {
   
   /* 自定义的内容实现 */}
            {
   
   item.name}
          </div>
        ))}
      </div>
      <span onClick={
   
   () => exportImages()}>导出图片</span>
    </>
  );
}

export default App;

为了便于理解,上述代码只保留了核心逻辑。

dom转图片base64Data

首先,我们要借助html2canvas遍历所有dom生成base64Data数据

const exportImages = async () => {
   
   
    // 循环遍历 commentRefs.current 数组中的每一个元素
    for (let i = 0; i < commentRefs.current.length; i++) {
   
   
        // 获取当前索引处的引用
        const ref = commentRefs.current[i];
        // 检查引用是否存在且索引 i 小于 commentRefs.current 的长度
        if (ref && i < commentRefs.current.length) {
   
   
            try {
   
   
                // 使用 html2canvas 库将 ref 元素转换为 Canvas 元素
                const canvas = await html2canvas(ref, {
   
    useCORS: true });
                // 将 Canvas 元素转换为 base64 格式的 PNG 图片数据 URL
                const dataUrl = canvas.toDataURL("image/png");
                // 从数据 URL 中提取 base64 编码的图片数据部分
                const base64Data = dataUrl.split(",")[1];
            } catch (error) {
   
   
                // 捕获任何导出图片时可能出现的错误,并输出到控制台
                console.error("Error exporting the comment as an image:", error);
            }
        }
    }
};

上述代码中,base64Data就是我们获取到的数据。

将base64Data写入压缩包

借助JSZip,我们可以把一些流数据进行打包,也可以将base64Data进行打包。

const exportImages = async () => {
   
   
    // 创建一个新的 JSZip 实例
    const zip = new JSZip();

    for (let i = 0; i < commentRefs.current.length; i++) {
   
   
        const ref = commentRefs.current[i];
        if (ref && i < commentRefs.current.length) {
   
   
            try {
   
   
                const canvas = await html2canvas(ref, {
   
    useCORS: true });RL
                const dataUrl = canvas.toDataURL("image/png");
                const base64Data = dataUrl.split(",")[1];
                // 将图片数据添加到 ZIP 文件中,使用 image{i+1}.png 作为文件名
                zip.file(`image${
     
     i + 1}.png`, base64Data, {
   
    base64: true });
            } catch (error) {
   
   
                console.error("Error exporting the comment as an image:", error);
            }
        }
    }

    // 生成 ZIP 文件并将其作为 Blob 对象返回
    const blob = await zip.generateAsync({
   
    type: "blob" });
  FileSaver.saveAs(blob, "images.zip");
};

这段代码扩展了之前的 exportImages 函数,添加了将生成的图片数据打包成 ZIP 文件的功能。关于JSZip的用法,大家可以看npm官网。这里我简单介绍下zip.file的用法。
zip.file 是 JSZip 库中用于向 ZIP 文件中添加文件的方法。它的基本用法是将数据添加到 ZIP 文件中,并指定文件的名称和数据。
基本语法

zip.file(fileName, data, options);
  • fileName: 要添加到 ZIP 文件中的文件名称,可以包含路径,例如 "images/image1.png"
  • data: 要添加的文件数据,可以是字符串、ArrayBuffer、Uint8Array 等,具体取决于你要添加的文件类型和数据格式。
  • options (可选): 是一个对象,可以包含以下选项:
    • base64 (boolean): 指定 data 是否为 base64 编码,默认为 false。如果 data 是 base64 编码的字符串,则需要设置为 true

      实现文件下载

      要实现文件下载,我们一般借助FileSaver。FileSaver 是一个用于在浏览器中保存文件的 JavaScript 库。它通常与生成的文件内容(如通过其他库生成的 Blob 对象)一起使用。
      基本用法
      ```
      import FileSaver from "file-saver";

FileSaver.saveAs(blob, fileName);


- `blob`: 要保存的文件内容,通常是通过其他操作生成的 Blob 对象。
- `fileName`: 下载文件的名称,可以包含文件扩展名,例如 `"example.txt"`。

因此,我们只需要在exportImages方法最后添加下面代码即可

FileSaver.saveAs(blob, "images.zip");

## 完整代码
### react版本
```javascript
import { useRef, useState } from "react";
import html2canvas from "html2canvas";
import JSZip from "jszip";
import FileSaver from "file-saver";
function App() {
  const commentRefs = useRef([]);
  const mockData = [
    { name: "张三", age: 18 },
    { name: "李四", age: 18 },
    { name: "王五", age: 18 },
    { name: "石小石", age: 18 },
  ];
  const exportImages = async () => {
    const zip = new JSZip();
    for (let i = 0; i < commentRefs.current.length; i++) {
      const ref = commentRefs.current[i];
      if (ref && i < commentRefs.current.length) {
        try {
          const canvas = await html2canvas(ref, {
            useCORS: true,
            backgroundColor: "rgba(255, 255, 255, 0.6)",
          });
          const dataUrl = canvas.toDataURL("image/png");
          const base64Data = dataUrl.split(",")[1];
          zip.file(`image${i + 1}.png`, base64Data, { base64: true });
        } catch (error) {
          console.error("Error exporting the comment as an image:", error);
        }
      }
    }
    const blob = await zip.generateAsync({ type: "blob" });
    FileSaver.saveAs(blob, "images.zip");
  };

  return (
    <>
    <div>
    {mockData.map((item, index) => (
      <div key={index} ref={(el) => (commentRefs.current[index] = el)}>
                  {/* 自定义的内容实现 */}
                  {item.name}
</div>
))}
  </div>
  <span onClick={() => exportImages()}>导出图片</span>
  </>
);
}

export default App;

vue版本

<template>
<div>
  <div v-for="(item, index) in mockData" :key="index" ref="setRef">
  <!-- 自定义的内容实现 -->
  {
   
   {
   
    item.name }}
</div>
  <span @click="exportImages">导出图片</span>
  </div>
  </template>

<script>
import {
   
    ref } from 'vue';
import html2canvas from 'html2canvas';
import JSZip from 'jszip';
import FileSaver from 'file-saver';

export default {
   
   
  setup() {
   
   
    // 使用 ref 创建响应式数据
    const commentRefs = ref([]);
    const mockData = [
      {
   
    name: '张三', age: 18 },
      {
   
    name: '李四', age: 18 },
      {
   
    name: '王五', age: 18 },
      {
   
    name: '石小石', age: 18 }
    ];

    // 导出图片的方法
    const exportImages = async () => {
   
   
      const zip = new JSZip();
      for (let i = 0; i < commentRefs.value.length; i++) {
   
   
        const ref = commentRefs.value[i];
        if (ref) {
   
   
          try {
   
   
            const canvas = await html2canvas(ref, {
   
   
              useCORS: true,
              backgroundColor: 'rgba(255, 255, 255, 0.6)'
            });
            const dataUrl = canvas.toDataURL('image/png');
            const base64Data = dataUrl.split(',')[1];
            zip.file(`image${
     
     i + 1}.png`, base64Data, {
   
    base64: true });
          } catch (error) {
   
   
            console.error('Error exporting the comment as an image:', error);
          }
        }
      }
      const blob = await zip.generateAsync({
   
    type: 'blob' });
      FileSaver.saveAs(blob, 'images.zip');
    };

    // 将引用存入 commentRefs 数组中
    const setRef = (el) => {
   
   
      commentRefs.value.push(el);
    };

    return {
   
   
      mockData,
      exportImages,
      setRef
    };
  }
};
</script>

总结

这篇文章介绍了如何使用html2canvs将多个dom转成base64Data图片数据,然后借助jszip进行打包,最后通过file-saver下载到本地的简单技术方案。借助这一套方案,其实也可以实现纯前端将网页转成pdf,最后下载成压缩包。
这篇文章中,没有做demo图片中的进度条功能,这个很简单,大家可以结合业务自行实现。

相关文章
|
30天前
|
存储 前端开发 JavaScript
🚀前端轻松实现网页内容转换:一键复制、保存图片及生成 Markdown
在现代前端开发中,提升用户的交互体验至关重要。本文将详细介绍如何使用 HTML2Canvas 和 Turndown 两个强大的 JavaScript 库,实现将网页选中文本转化为图片并保存或复制到剪贴板,或将内容转换为 Markdown 格式。文章包含核心代码实现、技术细节和功能拓展方向,为开发者提供了一个轻量级的解决方案,提升用户体验。
129 68
|
19天前
|
前端开发 API
前端界面生成PDF并导出下载
【10月更文挑战第21天】利用合适的第三方库,你可以在前端轻松实现界面生成 PDF 并导出下载的功能,为用户提供更方便的文档分享和保存方式。你还可以根据具体的需求进一步优化和定制生成的 PDF 文件,以满足不同的业务场景要求。
|
1月前
|
JavaScript 前端开发 Python
django接收前端vue传输的formData图片数据
django接收前端vue传输的formData图片数据
33 4
|
1月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
19 1
|
1月前
|
前端开发 JavaScript 编译器
不走弯路,纯前端如何把图片导出成视频!
【10月更文挑战第3天】不走弯路,纯前端如何把图片导出成视频!
42 3
|
1月前
|
JavaScript 前端开发 编译器
吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
【10月更文挑战第2天】吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
47 2
|
29天前
|
资源调度 前端开发 安全
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
73 0
|
30天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
127 2
|
30天前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
37 0
|
30天前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。