纯前端如何实现批量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图片中的进度条功能,这个很简单,大家可以结合业务自行实现。

相关文章
|
5天前
|
前端开发 Windows
【前端web入门第一天】02 HTML图片标签 超链接标签 音频标签 视频标签
本文档详细介绍了HTML中的图片、超链接、音频和视频标签的使用方法。首先讲解了`&lt;img&gt;`标签的基本用法及其属性,包括如何使用相对路径和绝对路径。接着介绍了`&lt;a&gt;`标签,用于创建超链接,并展示了如何设置目标页面打开方式。最后,文档还涵盖了如何在网页中嵌入音频和视频文件,包括简化写法及常用属性。
27 13
|
24天前
|
JSON JavaScript 前端开发
JS的无限可能: 前端 精妙DOM技巧至Node.js的服务端
JS的无限可能: 前端 精妙DOM技巧至Node.js的服务端
|
22天前
|
XML JavaScript 前端开发
哇塞!Web 前端惊现 DOM 元素神操作,一场惊心动魄的网页变革,你准备好了吗?
【8月更文挑战第23天】在Web前端开发中,熟练操作DOM元素至关重要。DOM作为一种编程接口,将HTML/XML文档表示为节点树,便于使用JavaScript访问及修改文档内容与结构。
40 0
|
22天前
|
JavaScript 前端开发 API
前端开发者的救赎:揭秘JQ对象与DOM元素的神秘转换术
【8月更文挑战第23天】在Web前端开发领域,jQuery(简称JQ)作为一款流行的JavaScript库,极大简化了HTML文档遍历、事件处理、动画及Ajax交互等操作。理解和掌握jQuery对象与DOM元素间的转换至关重要。
26 0
|
2月前
|
开发框架 前端开发 JavaScript
循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理
循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理
|
2月前
|
前端开发 JavaScript
前端 JS 经典:下载的流式传输
前端 JS 经典:下载的流式传输
30 1
|
2月前
|
JavaScript 前端开发 API
前端框架与库 - jQuery基础与DOM操作
【7月更文挑战第18天】jQuery 是一个简化JavaScript任务的库,以其“write less, do more”理念著称。核心功能包括DOM操作、事件处理和Ajax。DOM操作如选择元素(`$(&quot;p&quot;)`、`$(&quot;#myDiv&quot;)`、`$(&quot;.myClass&quot;)`)、创建及添加元素、修改属性和内容。事件处理如绑定(`click`)和触发(`trigger`)。常见问题涉及`$`符号冲突(使用`jQuery`代替)、异步加载管理和选择器性能优化。了解并规避这些问题能提升jQuery使用效率。
22 0
|
2月前
|
前端开发 JavaScript
Vue前端渲染blob二进制对象图片的方法
Vue前端渲染blob二进制对象图片的方法
160 0
|
2月前
|
JavaScript 前端开发
【vue】 接口返回的preview是张图片,前端如何渲染
【vue】 接口返回的preview是张图片,前端如何渲染
106 0
|
2月前
|
前端开发
支付系统--微信支付21--搭建前端环境,payment-demo-front这个项目文件夹是前端显示文件,payment-demo是后端项目,支付页面常见三个页面:购买课程,我的订单,下载账单
支付系统--微信支付21--搭建前端环境,payment-demo-front这个项目文件夹是前端显示文件,payment-demo是后端项目,支付页面常见三个页面:购买课程,我的订单,下载账单