Coder Social home page Coder Social logo

react-simple-upload's Introduction

react-simple-upload

一个基于 simple-uploader.js 的 react 的上传组件,是vue-simple-uploader的 react 实现,并对秒传和断点续传做了一些优化方案。

在线体验(账号:test;密码:test)

特性

  • 支持文件、多文件、文件夹上传

  • 支持拖拽文件、文件夹上传

  • 统一对待文件和文件夹,方便操作管理

  • 可暂停、继续上传

  • 错误处理

  • 支持“快传”,通过文件判断服务端是否已存在从而实现“快传”

  • 支持断点续传,通过文件判断服务端存在已上传的文件切片,只上传未上传的切片

  • 上传队列管理,支持最大并发上传

  • 分块上传,并发控制

  • 支持进度、预估剩余时间、出错自动重试、重传等操作

安装

npm i react-simple-upload

使用

样式为默认样式,需要定制样式请看例子

import Uploader from 'react-simple-upload';
import { UploadFile } from 'react-simple-upload/dist/types';
export default function Upload() {
  const [options] = useState({
    target: '//localhost:3000/upload',
    testChunks: false
  });
  const complete = () => {
    console.log('complete');
  };
  return <Uploader options={options}></Uploader>;
}

组件

Uploader

上传根组件,可以直接使用选择其默认样式,也可以使用 UploaderBtn 等组件自定义样式及结构

API

参数 说明 类型 默认值
options simple-uploader.js uploader实例配置 UploadeOptions simple-uploader.js文档
fileStatusText 用于转换文件上传状态文本映射对象。
object | function(status:"success"|"error"|"uploading"|"paused"|"waiting",response):string
{
  "success": "success",
  "error": "error",
  "uploading": "uploading",
  "paused": "paused",
  "waiting": "waiting"
}
autoStart 是否选择文件后立即上传 Boolean

true

onFileAdded 这个事件一般用作文件校验,如果说返回了 false,那么这个文件就会被忽略,不会添加到文件上传列表中
(file: UploadFile) => boolean;
(file) => true;
onFilesAdded fileAdded 一样,但是一般用作多个文件的校验
(files: UploadFile[], fileList: UploadFile[]) => boolean;
() => true;
onFilesSubmitted 和 filesAdded 类似,但是是文件已经加入到上传列表中,一般用来开始整个的上传
(files: UploadFile[],fileList: UploadFile[],e: Event) => void;
() => {};
onFileProgress 一个文件正在上传
(rootfile: UploadFile,file: UploadFile,chunk: UploadChunk) => void;
()=>void
onFileSuccess 文件上传成功事件,rootFile 就是成功上传的文件所属的根 Uploader.File 对象,它应该包含或者等于成功上传文件; file 就是当前成功的 Uploader.File 对象本身;message 就是服务端响应内容,永远都是字符串;chunk 就是 Uploader.Chunk 实例,它就是该文件的最后一个块实例,如果你想得到请求响应码的话,chunk.xhr.status 就是。
 (rootFile: UploadFile,file: UploadFile,message: string,chunk: UploadChunk) => void;
() => {};
onFileComplete 一个根文件(文件夹)成功上传完成。
(rootFile: UploadFile) => void
() => {};
onComplete 上传完毕
() => void
() => {};
onFileRemove 一个文件(文件夹)被移除
(file: UploadFile) => void;
() => {};
onFileRetry 文件重试上传事件
 (rootFile: UploadFile,file: UploadFile,chunk: UploadChunk) => void
() => {};
onFileError 上传过程中出错了
(rootFile: UploadFile,file: UploadFile,message: string,chunk: UploadChunk)=>void;
() => {};
children 自定义样式时使用,类似Vue的作用域插槽
({ fileList }: { fileList: UploadFile[] }) => JSX.Element;
-

UnSupport

当前浏览器是否支持 File API 上传,不支持时作提示使用

API

参数 说明 类型 默认值
children 不支持File API上传时的提示信息
JSX.Element;
<p>你的浏览器等级过低暂不支持上传组件</p>

UploaderDrop

拖拽上传组件

API

参数 说明 类型 默认值
children 拖拽上传组件区域内显示的内容,一般直接存放上传按钮
JSX.Element;
<p className="m-3">把文件拖拽到此处进行上传</p>
<div className="flex">
  <UploaderBtn>选择文件</UploaderBtn>
  <UploaderBtn directory={true}>选择文件夹</UploaderBtn>
</div>

UploaderBtn

点击上传文件按钮

API

参数 说明 类型 默认值
children 上传按钮中的内容
JSX.Element | string;
-
directory 是否上传文件夹 Boolean false
single 是否一次只能选择一个文件夹 Boolean false

UploaderList

文件文件夹列表

API

参数 说明 类型 默认值
children 类Vue作用域插槽 应该返回UploadFile组件或自定义文件组件使用
({ fileList }: { fileList: UploadFile[] }) => JSX.Element;
<ul>
  {fileList.map((file) => (
    <UploaderFile key={file.id} file={file} list={true}>
    </UploaderFile>
   ))}
</ul>
fileList 文件列表 UploadFile[] -

UploadFile

文件 文件夹单个组件

API

参数 说明 类型 默认值
file 文件对象 UploadFile -
children 文件组件的类Vue作用域插槽 返回新的自定义的上传组件
  • name: 文件名
  • size: 文件大小
  • averageSpeed: 平均上传速度
  • error: 是否发生错误
  • paused:是否暂停
  • isComplete:是否上传完毕
  • isUploading:是否正在上传
  • progress:上传进度(0-1)
  • formatedTimeRemaining:剩余时间
  • status:文件当前状态
  • statusText:文件状态转化的业务上传对应状态
  • fileAdded:文件类型
  • pause:上传暂停方法
  • retry:上传重试方法
  • resume:上传继续方法
  • remove:上传移除方法
(fileInfo: {
  name: string;
  size: string;
  averageSpeed: string;
  error: boolean;
  paused: boolean;
  isComplete: boolean;
  isUploading: boolean;
  progress: number;
  formatedTimeRemaining: string;
  status: 'success' | 'error' | 'uploading' | 'paused' | 'waiting';
  statusText: string;
  fileCategory: string;
  pause: () => void;
  retry: () => void;
  resume: () => void;
  remove: () => void;
}) => JSX.Element;
-

例子

例子主要包含自定义样式 以及 断点续传和秒传的实现

  1. 定制样式仅做参考 案例演示的 css 类使用的是 tailwindcss 可以自行调整样式

  2. 断点续传和秒传 需要配合服务端共同实现,可以参考react-admin-background的实现

    • 首先配置 testChunks,checkChunkUploadedByResponse 函数如下
    • testChunks 为 true 时每次上传文件前先发送一个 url 为"/uploadChunk"的 get 请求,判断文件及切片的上传情况,返回值主要是 skip 字段和 uploaded 字段
      • skip:boolean 字段判断是否需要秒传,skip:true,表明文件上传过,直接秒传即可
      • uploaded:number[] 字段表明已经上传过的切片
    • checkChunkUploadedByResponse:这个函数在每个切片正式上传前触发,chunk 参数是当前的切片,message 是 get 请求返回的字符串形式的结果,如果返回 true 表明该切片成功上传,不需要重复上传

    秒传

    断点续传

  3. 关于 merge 这个请求:这个请求可以根据后端业务需求考虑是否需要单独添加,实际后端服务器是可以在切片上传完成后自动进行合并操作。

import { Divider, Space } from 'antd';
import {
  CaretRightOutlined,
  ReloadOutlined,
  PauseOutlined,
  CloseOutlined
} from '@ant-design/icons';
import { useState } from 'react';
import Uploader, {
  UnSupport,
  UploaderBtn,
  UploaderDrop,
  UploaderFile,
  UploaderList
} from 'react-simple-upload';
import { UploadFile, UploadChunk } from 'react-simple-upload/dist/types';
export default function Upload() {
  const [options] = useState({
    target: '//localhost:3000/uploadChunk',
    // 秒传测试,为true进行一次get请求判断上传的内容
    testChunks: true,
    // 每个chunk进行上传前的校验工作,返回true表明该chunk进行上传
    checkChunkUploadedByResponse: (chunk: UploadChunk, message: string) => {
      const { data } = JSON.parse(message);
      if (data.skip) {
        return true;
      }
      return (data.uploaded || []).indexOf(chunk.offset + 1) >= 0;
    }
  });
  // 所有切片上传完成时进行文件合并操作
  const fileComplete = (rootFile: UploadFile) => {
    // 文件夹上传时的合并方式
    if (rootFile.isFolder) {
      for (const file of rootFile.files) {
        merge({
          identifier: file.uniqueIdentifier,
          filename: file.name,
          uploadBy: userId,
          size: file.size
        });
      }
    } else {
      // 文件上传时的合并方式
      merge({
        identifier: uploadTool.cleanIdentifier(rootFile.uniqueIdentifier),
        filename: rootFile.name,
        uploadBy: userId,
        size: uploadTool.transferSize(rootFile.size)
      });
    }

    console.log(rootFile, 'fileComplete');
  };
  const complete = () => {
    console.log('complete');
  };
  return (
    <Uploader
      options={options}
      onFileComplete={fileComplete}
      onComplete={complete}
    >
      {({ fileList }) => (
        <>
          <UnSupport></UnSupport>
          <UploaderDrop>
            <>
              <p>拖拽上传</p>
              <div className="flex mt-2">
                <UploaderBtn>选择文件</UploaderBtn>
                <UploaderBtn directory={true}>选择文件夹</UploaderBtn>
              </div>
            </>
          </UploaderDrop>
          <UploaderList fileList={fileList}>
            {() => (
              <>
                {fileList.map((file) => (
                  <UploaderFile file={file} list={true} key={file.id}>
                    {({
                      name,
                      size,
                      averageSpeed,
                      pause,
                      retry,
                      remove,
                      resume,
                      formatedTimeRemaining,
                      error,
                      isComplete,
                      isUploading,
                      paused,
                      status,
                      statusText,
                      progress,
                      fileCategory
                    }) => (
                      <div className="uploader-file flex ">
                        <span className="flex-1">{fileCategory}</span>
                        <span className="flex-1">{name}</span>
                        <span className="flex-1">{size}</span>
                        <span className="flex-1">
                          {isUploading ? (
                            <>
                              <span>{Math.floor(progress * 100) + '%'}</span>
                              <span className="mx-3">{averageSpeed}</span>
                              <span>{formatedTimeRemaining}</span>
                            </>
                          ) : (
                            statusText
                          )}
                        </span>
                        {isUploading && (
                          <div className="flex-1 flex items-center justify-center ">
                            <Space>
                              <PauseOutlined onClick={pause} />
                              <CloseOutlined onClick={remove} />
                            </Space>
                          </div>
                        )}
                        {error && (
                          <span
                            className="flex-1 flex items-center justify-center "
                            onClick={retry}
                          >
                            <ReloadOutlined />
                          </span>
                        )}
                        {paused && (
                          <span
                            className="flex-1 flex items-center justify-center "
                            onClick={resume}
                          >
                            <CaretRightOutlined />
                          </span>
                        )}
                      </div>
                    )}
                  </UploaderFile>
                ))}
              </>
            )}
          </UploaderList>
        </>
      )}
    </Uploader>
  );
}

react-simple-upload's People

Contributors

sunburst89757 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.