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

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

theme: smartblue

往期精彩文章:

用云编译器半小时完成轮播组件紧急开发!被公司奖励500!

直接使用git pull拉取代码,被同事狠狠地diss了!

快收藏!超实用标签title属性重写,让同事对你刮目相看

需求背景

这几天捣鼓一些小东西,需要实现这样一个功能:将页面指定的dom批量下载成压缩包。功能大致如下:

将每条评论信息转成图片,然后放到一个压缩包里下载下来。

压缩包内容

这篇文章就简单介绍下,我是如何实现的。

技术思路

要将dom转成图片,我们直接使用html2canvas就可以;要将所有图片放到压缩包里,我们首先获取到每个图片的

base64Data编码信息,最后借助jszip就可以实现。

技术方案

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

使用云编译器进行调试

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

https://juejin.cn/post/7388753413309349903 (见文末)

必要依赖安装

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版本

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

相关文章
|
12天前
|
存储 前端开发 JavaScript
🚀前端轻松实现网页内容转换:一键复制、保存图片及生成 Markdown
在现代前端开发中,提升用户的交互体验至关重要。本文将详细介绍如何使用 HTML2Canvas 和 Turndown 两个强大的 JavaScript 库,实现将网页选中文本转化为图片并保存或复制到剪贴板,或将内容转换为 Markdown 格式。文章包含核心代码实现、技术细节和功能拓展方向,为开发者提供了一个轻量级的解决方案,提升用户体验。
110 68
|
1天前
|
前端开发 API
前端界面生成PDF并导出下载
【10月更文挑战第21天】利用合适的第三方库,你可以在前端轻松实现界面生成 PDF 并导出下载的功能,为用户提供更方便的文档分享和保存方式。你还可以根据具体的需求进一步优化和定制生成的 PDF 文件,以满足不同的业务场景要求。
|
17天前
|
JavaScript 前端开发 Python
django接收前端vue传输的formData图片数据
django接收前端vue传输的formData图片数据
18 4
|
15天前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
12 1
|
19天前
|
前端开发 JavaScript 编译器
不走弯路,纯前端如何把图片导出成视频!
【10月更文挑战第3天】不走弯路,纯前端如何把图片导出成视频!
34 3
|
11天前
|
资源调度 前端开发 安全
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
19 0
|
25天前
|
JavaScript
DOM 节点列表长度(Node List Length)
DOM 节点列表长度(Node List Length)
|
5天前
|
JavaScript
HTML DOM 节点树
HTML DOM 节点是指在 HTML 文档对象模型中,文档中的所有内容都被视为节点。整个文档是一个文档节点,每个 HTML 元素是元素节点,元素内的文本是文本节点,属性是属性节点,注释是注释节点。DOM 将文档表示为节点树,节点之间有父子和同胞关系。
|
5天前
|
JavaScript
HTML DOM 节点
HTML DOM(文档对象模型)将HTML文档视为节点树,其中每个部分都是节点:文档本身是文档节点,HTML元素是元素节点,元素内的文本是文本节点,属性是属性节点,注释是注释节点。节点间存在父子及同胞关系,形成层次结构。
|
15天前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
XML DOM 遍历节点树