如何使react-dropzone中的预览与图像以外的文件一起使用?

问题描述 投票:0回答:1

我需要帮助如何使 react-dropzone NPM 包使上传的文件显示图像文件以外的文件的预览(*.png、*.jpg/jpeg、*.gif 等 - 这些都会生成预览就好)。

目前,当我使用 Dropzone 在 Web 表单上上传随附文件时,如果我上传图像文件(*.png、*.jpg 等),我们设置的预览就可以正常显示,并带有一个小缩略图已上传文件。 (见下图)

但是,如果我上传其他类型的文件,例如 MS-Outlook *.docx、*.xlsx,或者 Adobe Acrobat *.pdf,它只会给我一个空白框,其中包含损坏的文件图像和其他内容

alt="..."
我在那里输入的文本,在本例中为“上传的文件预览”。 (见下图)

我们使用的代码几乎是从 React Dropzon 网站上的 Preview 示例中逐字复制的,所以我想知道我是否在这里遗漏了一些东西?

这是我尝试过的—

  1. 创建一个
    react-dropzone
    <Dropzone>
    页面,将其设置为接受 any 文件类型,并使其能够使用来自 https://react-dropzone.js.org/#previews 的代码进行预览,在代码的
    <aside>
    部分底部有“预览”
    <Dropzone>
  2. 拖放任何类型的图像文件(*.png、*.jpg 或 *.jpeg、*.gif 等)。
  3. 查看出现的预览(应该没问题,图像文件的缩略图)。
  4. 现在将任何其他类型的文件(.doc.xls、*.pdf 等)拖放到
    <Dropzone>
  5. 查看该文件出现的预览(应该是空白的,带有“损坏的文件”图像以及其中描述该文件的任何
    alt="..."
    文本)。

Dropzone 在文件顶部导入—

import React, { Component, /* useCallback */ } from "react";
...
import Dropzone from "react-dropzone";
...

缩略图的样式/CSS 代码 —

...
const thumbsContainer = {
  display: "flex",
  flexDirection: "row",
  flexWrap: "wrap",
  marginTop: 16
};

const thumb = {
  display: "inline-flex",
  borderRadius: 2,
  border: "1px solid #eaeaea",
  marginBottom: 8,
  marginRight: 8,
  width: 100,
  height: 100,
  padding: 4,
  boxSizing: "border-box"
};

const thumbInner = {
  display: "flex",
  minWidth: 0,
  overflow: "hidden"
};

const img = {
  display: "block",
  width: "auto",
  height: "100%"
};
...

onDrop()
回调函数—

...
onDrop = (acceptedFiles, rejectedFiles) => {
  let files = acceptedFiles.map(async file => {
    let data = new FormData();
    data.append("file", file);

    let item = await axios
      .post("form/upload", data, {
        headers: {
          "X-Requested-With": "XMLHttpRequest",
          "Content-Type": "application/x-www-form-urlencoded"
        }
      })
      .then(response => {
        return Object.assign(file, {
          preview: URL.createObjectURL(file),
          filename: response.data.filename
        });
      })
      .catch(err => {
        let rejects = rejectedFiles.map(async file => {
          let data = new FormData();
          await data.append("file", file);

          console.log("There was an error while attempting to add your files:", err);
          console.log("The files that were rejected were:\n", rejects.join('\n'));
        })
      });
    return item;
  });
  Promise.all(files)
    .then(completed => {
      let fileNames = completed.map(function(item) {
        return item["filename"];
      });
      this.setState({ files: completed, fileNames: fileNames });
    })
    .catch(err => {
      console.log('DROPZONE ERROR:', err);
    });
  };
...

在 React.JS 中使用

<Dropzone>
的实际 JSX 代码
return()

...
<Form.Field>
  <label>Upload Files or Screenshots</label>
  <Dropzone accept={acceptedFileTypes} onDrop={this.onDrop}>
    {({ getRootProps, getInputProps, isDragActive }) => {
      return (
        <div
          {...getRootProps()}
          className={classNames("dropzone", {
            "dropzone--isActive": isDragActive
          })}
        >
          <input {...getInputProps()} />
          {isDragActive ? (
            <div>
              <div className="centered">
                <Icon name="cloud upload" size="big" />
              </div>
              <div className="centered">Drop Files Here.</div>
              <div className="centered">
                <Button className="drop-button">
                  Or Click to Select
                </Button>
              </div>
            </div>
          ) : (
            <div>
              <div className="centered">
                <Icon name="cloud upload" size="big" />
              </div>
              <div className="centered">
                Drag and Drop Supporting Files here to Upload.
              </div>
              <div className="centered">
                <Button className="drop-button">
                  Or Click to Select
                </Button>
              </div>
            </div>
          )}
        </div>
      );
    }}
  </Dropzone>
  <aside style={thumbsContainer}>{thumbs}</aside>
</Form.Field>
...

预期行为 —

我会更喜欢所有文件类型来生成正确的预览。

我的设置 —

  • MacBook Pro 13 英寸 2018
  • 2.7 GHz Intel Core i7 处理器
  • 16 GB 2133 MHz LPDDR3 RAM 内存
  • MacOS 版本 10.14.4
  • React 和 React-DOM 版本 16.5.2
  • Node.JS 版本 10.15.2
  • 纱线版本1.15.2
  • React Dropzone 版本 10.1.4
  • 适用于 Mac OS 的 Google Chrome 浏览器版本 74.0.3729.131(官方版本)(64 位)
  • 上传到AWS EC2实例容器服务器。

...那么,我是否做错了什么,导致除图像之外的其他文件的预览无法正常工作?除了图像文件之外,这不是其他功能吗?请指教。

还有几个问题 —

  1. 如果无法为除具有
    react-dropzone
    的图像文件以外的文件生成预览,是否有办法让图像文件生成预览,但所有其他文件仅列出正在上传的文件名等,如某些您的 React Dropzone 网站 上的其他示例?如果是这样,当您将文件拖放到
    <Dropzone>
    上时,如何在两者之间切换以同时拥有两者?
  2. 在我们的代码中,我们几乎逐字复制了 React Dropzone 网站 上的示例,我们注意到,当您将一组文件拖放到
    <Dropzone>
    上,然后尝试拖动并第二次投放时,会擦除第一组上传的文件,并将其替换为刚刚投放到
    <Dropzone>
    上的新文件。有没有办法让
    <Dropzone>
    在每次将文件拖放到那里时累积添加文件,而不仅仅是清除以前的文件并替换为新文件?如果是这样,请问步骤是什么?
  3. 有没有办法,在所有其他文件的文件预览为空白框的情况下,摆脱“损坏的文件”图标?

我非常感谢任何建设性的答复。预先感谢您。

javascript reactjs upload preview react-dropzone
1个回答
0
投票

澄清一下,React-dropzone 并不是在页面上显示预览的。您正在使用图像标签来做到这一点。
现在,如果您要求显示所有文档文件类型的预览,您首先需要一个所需类型的解析器,因为浏览器不支持读取 pdf 以外的文档(.doc/.xlsx)。
类似于 react-doc-viewer

这样您就可以读取上传的文件并使用包渲染器来显示文件

const docs = [
    { uri: "https://url-to-my-pdf.pdf" },
    { uri: require("./example-files/pdf.pdf") }, // Local File
];
... 
<DocViewer documents={docs} />;
  1. 如果您不想安装库来执行此操作而只需要显示文件名,则只需更改显示所选文件的代码部分即可。
const thumbs = files.map(file => {
  // Add other images types as needed
  if(["image/png", "image/jpeg"].includes(file.type)){
    return (
      <div style={thumb} key={file.name}>
        <div style={thumbInner}>
          <img
            src={file.preview}
            style={img}
            // Revoke data uri after image is loaded
            onLoad={() => { URL.revokeObjectURL(file.preview) }}
          />
        </div>
      </div>
    );
  }
  // Handling other file types
  return (
    <div style={thumb} key={file.name}>
      <div style={thumbInner}>
        <p>{file.name}</p
      </div>
    </div>
  );
});

您可以为不同的文件 MIME 类型添加不同的条件。
文件 mime 类型的完整列表可以在 mdn docs

中找到
  1. 如果要将数据追加到同一个列表中,则需要更改 onDrop() 函数,因为在 Promise 解析部分中您将覆盖列表。
let fileNames = [...this.state.filenames, 
   ...completed.map(function(item) {
     return item["filename"];
})];
this.setState({files: [...this.state.files, ...completed], fileNames: fileNames });
  1. 第 1 部分应该解决这个问题
© www.soinside.com 2019 - 2024. All rights reserved.