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

相关文章
|
26天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
2天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
308 14
|
18天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
5天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
20天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
22天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2584 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
4天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
177 2
|
2天前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
102 65
|
6天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
283 2
|
22天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1580 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码