灏天阁

React 中使用 createObjectURL 的实践经验

· Yin灏

在 Web 开发中,我们经常需要让用户下载一些文件,比如 PDF、图片、音频、视频等。常见的方式是让后台服务器返回文件数据流,然后我们通过 a 标签的 download 属性实现下载。这种方式需要后台的支持,同时也有一些限制,比如无法下载跨域的文件等。

那么有没有一种方式可以在前端直接实现文件下载呢?

答案是肯定的,通过 createObjectURL 方法就能实现在前端下载文件而不需要后台服务支持。

本文将详细介绍如何在 React 中使用 createObjectURL 实现前端文件下载的功能。

依照惯例,先看效果再讲方法~

前端下载示例.gif

createObjectURL 方法

createObjectURLURL 对象的一个方法,用于将二进制数据或 Blob 对象转换为可用于页面上的 URL,通常用于预览或下载文件,或者在页面上显示来自相机或麦克风的实时流数据。生成的 URL 对象可以直接用于图片、音频、视频等媒体元素的 src 属性中,也可以用于下载文件的链接地址。

使用 createObjectURL 方法生成的 URL 对象是唯一的,只要页面关闭或重新加载,它就会失效。为了避免内存泄漏,建议在使用完毕后调用 URL.revokeObjectURL 方法,将其释放。

下载文本文件示例

下面以下载文本文件为例,介绍如何在 React 中使用 createObjectURL 方法实现文件下载的功能。

首先,我们通过 Blob 对象将文本内容转换为二进制数据。比如,我们将一个字符串转换为 Blob 对象:

const content = "这是一个文本文件中的内容";
const blob = new Blob([content], { type: "text/plain" });

之后,我们将内容放在一个 txt 文件中下载到本地:

import React, { useState } from "react";

function DownloadButton() {
  const [content, setContent] = useState("这是一个文本文件中的内容");

  const handleClick = () => {
    const blob = new Blob([content], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "file.txt";
    document.body.appendChild(link);
    link.click();
    URL.revokeObjectURL(url);
    document.body.removeChild(link);
  };

  return <button onClick={handleClick}>下载文件</button>;
}

export default DownloadButton;

下面是效果图:

前端下载示例.gif

在上面的代码中,我们使用 useState 钩子函数定义了一个 state,用来保存文本文件的内容。在按钮的点击事件函数中,我们首先使用 Blob 对象将文本内容转换为二进制数据,然后使用 createObjectURL 方法将其转换为 URL 对象。

接着,创建一个下载链接,将 URL 对象设置到其 href 属性中,然后模拟用户点击链接来下载文件。最后,释放 URL 对象并从页面中移除下载链接。

需要注意的是,由于 React 中的事件处理程序会自动绑定 this,因此在事件处理程序中无法直接使用 document 对象和其他全局变量。

为了解决这个问题,我们可以使用 useRef 钩子函数创建一个 ref,将链接元素添加到 ref.current 中。在组件销毁时,使用 useEffect 钩子函数移除链接元素。

以下是一个使用 ref 属性的示例代码:

import React, { useState, useRef, useEffect } from "react";

function DownloadButton() {
  const [content, setContent] = useState("这是一个文本文件中的内容");
  const linkRef = (useRef < HTMLAnchorElement) | (null > null);

  const handleClick = () => {
    const blob = new Blob([content], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "file.txt";
    linkRef.current = link;
    document.body.appendChild(link);
    link.click();
    URL.revokeObjectURL(url);
  };

  // 组件销毁时手动从页面中移除下载链接
  useEffect(() => {
    return () => {
      if (linkRef.current) {
        document.body.removeChild(linkRef.current);
      }
    };
  }, []);

  return <button onClick={handleClick}>下载文件</button>;
}

export default DownloadButton;

在以上代码中,我们使用 useRef 钩子函数创建一个 ref,将链接元素添加到 ref.current 中。在组件销毁时,使用 useEffect 钩子函数移除链接元素。

总结

本文介绍了如何在 React 中使用 createObjectURL 方法实现文件下载的功能。使用 createObjectURL 方法可以让我们在前端轻松地实现文件下载、预览或播放等功能,而无需后台服务器的支持。当然,对于大文件或需要保护的文件,仍然建议你使用后台服务器的方式来实现下载。

- Book Lists -