应用场景
功能定位
FilePond 是一个灵活的文件上传库,可以拖入上传文件,并且会对图像进行优化以加快上传速度。让用户体验到出色、进度可见、如丝般顺畅的用户体验!能在大文件分片上传场景下,集成了上传、重传、删除等多种功能。
www.jianshu.com/p/1565067eb...
特点优势
- 上传内容:支持目录、文件、多个文件、本地路径、远程 URL 等。
- 文件管理:删除文件、选择文件、复制和粘贴文件、或使用 API 方式添加文件。
- 上传方式:使用 AJAX 进行异步上传、或将文件编码为 base64 数据用表单发送、分片上传。
- 图像优化:自动调整图像大小、裁剪和修复 EXIF 方向。
- 响应式:可在移动和桌面设备上使用。
- 插件:拥有多样、强大的插件,定制化不同需求
插件生态
FilePond 该库拥有多样、强大的插件部分,可以根据自己的需求选择插件组合起来使用,部分常用插件如下所示:
- File Rename:重命名客户端上的文件
- File Encode:将文件编码为 base64 数据
- File size Validation:文件大小验证工具
- File Type Validation:文件类型验证工具
- File Metadata:限制要添加的文件类型
- File Poster:在文件项目中显示图像
- Image Preview:显示图像文件的预览
- Image Edit:手动编辑图像文件
- Image Crop:设置图像文件的裁剪比例
- Image Resize:设置图像文件的输出尺寸
- Image Transform:上传之前在客户端上图像变换
- Image EXIF Orientation:提取 EXIF 方向信息
- Image Size Validation:限制要添加的图像的尺寸
- Image Filter:将颜色矩阵应用于图像像素
注:完整的插件列表及对应插件 API 文档链接,请查看 👇👇👇
引入插件的基本步骤:
- 引入 CSS 文件(部分插件有 CSS 文件)
- 引入 JS 文件
- 注册插件
- 配置插件(部分插件需配置)
常用的插件使用方法:
- destroys:销毁实例
- find:返回附加提供的元素的实例
- getOptions:返回当前的配置项
- supported:鉴别浏览器是否支持 FilePond
生态环境
FilePond 作为一个出色的 JavaScript 库,其在不同项目框架、项目库中,有着出色且丰富的集成生态,如上图所示的 jQuery、React、Vue、Angular、Svelte 等。
我们重点关注 FilePond 本身!
filepond
名称 | 链接 |
---|---|
npm | www.npmjs.com/package/fil... |
官网 | pqina.nl/filepond/ |
github | github.com/pqina/filep... |
vue-filepond
名称 | 链接 |
---|---|
npm | www.npmjs.com/package/vue... |
官网 | pqina.nl/filepond/do... |
github | github.com/pqina/vue-f... |
流程设计
上传基本流程
用 FilePond 异步上传文件,被成为 Processing: 简而言之,就是 FilePond 发送一个文件至服务端 server ,期望服务端返回一个唯一的文件 id(a unique file id)
下图详细介绍 Processing 的基本流程(以上传 my-file.png 为例)
- FilePond 以 multipart/form-data 形式,发送 POST 请求,上传文件 my-file.jpg
- server 将此文件保存在唯一的位置 tmp/12345/my-file.jpg
- server 以 text/plain 形式,返回给 FilePond 一个唯一位置 id 12345
- FilePond 把这个唯一位置 unique id 12345 ,存储至隐藏的 input 标签字段内
- client 用户提交包含带 unique id 的 input 选项的完整表单
- server 通过 unique id 移动 temp/12345 下的 my-file.jpg 文件,至最终位置 xxx 下,然后再移除掉原临时文件夹 tmp/12345
分片上传流程
- 为了以 切片(chunk) 形式上传文件(process file ),需要设置 chunkUploads 为 true
- FilePond 会对大于 chunkSize 的文件,进行分片
- 对于小于 chunkSize 的文件,会被直接发送到 process 接口
- 若想强制所有文件都被以切片形式上传,只需设置 chunkForce 为 true 即可
在 *分片上传场景(或称 Process Chunks) *下,在 接口请求中 需包含自定义 Header 如下:
Header | Description |
---|---|
Upload-Length | 被传输文件的总字节数 |
Upload-Name | 被传输文件的名称 |
Upload-Offset | 被传输切片的字节偏移量 |
Content-Type | patch 请求的内容类型,设定为'application/offset+octet-stream' |
简易流程
- FilePond 将通过发送一个 POST 请求(不带文件数据,并在请求头中携带 Upload-Length ),以开启分片上传!并期望从接口响应中拿到一个唯一的传输 id
- FilePond 将通过发送一个 PATCH 请求,向服务端推送一个切片。未来的每个切片推送请求,都将携带 Content-Type、Upload-Offset、Upload-Name、Upload-Length
- FilePond 将通过发送一个 HEAD 请求,获取哪些切片已经被上传,并期望从 响应头 中的 Upload-Offset 中,获取到下一个切片的文件偏移量
详细流程
- FilePond 向 server 请求一个唯一的传输 id(transfer id ),用来标识未来文件传输的唯一位置。这个请求默认以 POST 方法发送,并在请求头中携带要上传文件的总字节数,即 Upload-Length
- server 收到请求后,便会创建唯一的位置(目录)tmp/12345/ ,用于存放未来的文件切片
- server 将刚创建唯一位置,对应的 id 12345 ,以 text/plain 形式作为接口响应内容
- FilePond 拿到接口响应后,将其存储至 File Item(FilePond 对 file 的二次封装) 中
自此,命运的齿轮开始转动......
- FilePond 通过一个携带 unique id 12345 的 PATCH 请求,开始上传第一个切片!所有切片上传的 PATCH 请求,都会在请求头中携带 Upload-Offset、Upload-Length、Upload-Name
- FilePond 在所有切片都被成功上传前,会依次发送切片上传请求
- server 在所有切片都被上传成功后,会主动根据切片,创建文件
- 当所有切片都被成功上传,FilePond 会将 unique id 12345 存储至 <fieldset > 标签下的 <input > 中,作为该文件的 server id(用于 revert/remove 等操作)
- (非必须) client 提交 FilePond 表单( 下所有的 上的 unique id)
- server 通过 unique id ,移动 tmp/12345/my-file.jpg 到最终的目标位置,并将删除临时文件夹 tmp/12345
如果过程中,有一个切片上传失败了!FilePond 默认会重试 3 次(chunkRetryDelays 为 [500,1000,3000] )
若在 3 次重试,仍失败,重试的权利则交给用户
用户重试时,FilePond 会这样处理:
- 因为 FilePond 会记住在上传过程中,先前的 transfer id 12345 ,重试时,FilePond 会以一个 HEAD 请求开始,并在请求 URL 中,携带该 transfer id
- server 响应该请求时,在响应头中,携带期望的下一个切片的字节偏移量 Upload-Offset
- FilePond 将所有具有低于 Upload-Offset 偏移量的块标记为已完成,并从请求偏移量处,继续上传块
如下图所示:
常用 API
导出模块 Exports
我们在项目中,通过 import 导入 filepond 后,得到的是一个 完整的对象 FilePond,该对象暴露(export)了多类模块。
引入这些导出的模块,有下面的两种方式(以导入 supported 方法为例)
- 方式一
js
import FilePond from 'filepond'
const supported = FilePond.supported
- 方式二
js
import { supported } from 'filepond'
暴露的导出模块,常常以 方法(Methods )、枚举(Enums)的形式存在
方法 Methods
Method | Description |
---|---|
create(element, options) | 创建一个 FilePond 实例,两个入参都是可选,非必填的 |
destroy(element) | 销毁绑定在指定元素上的 FilePond 实例 |
find(element) | 查找绑定在指定元素上的 FilePond 实例 |
parse(context) | 解析 class 含 .filepond 的 DOM 片段,并将其转换为 FilePond 元素 |
registerPlugin(plugin) | 注册一个 FilePond 插件,以供后用 |
setOptions(options) | 为 FilePond 实例,设置页面级别默认配置 options |
getOptions() | 返回当前默认配置 options |
supported() | 判断当前浏览器是否支持 FilePond |
javascript
import { supported } from 'filepond'
const can = supported() // 判断当前浏览器是否支持 FilePond
console.log(can)
typescript
<input type="file" class="filepond" />
<script>
FilePond.parse(document.body);
</script>
枚举 Enums
Property | Description |
---|---|
Status | 与 FilePond 的 status 属性,共同使用,决定当前 FilePond 实例的状态 |
FileOrigin | 与 File Item 的 origin 属性,共同使用,决定 File Item 的来源 |
FileStatus | 与 File Item 的 status 属性,共同使用,决定 File Item 的状态 |
OptionTypes |
yaml
{
EMPTY: 0,
IDLE: 1,
ERROR: 2,
BUSY: 3,
READY: 4
}
yaml
{
INIT: 1,
IDLE: 2,
PROCESSING_QUEUED: 9,
PROCESSING: 3,
PROCESSING_COMPLETE: 5,
PROCESSING_ERROR: 6,
PROCESSING_REVERT_ERROR: 10,
LOADING: 7,
LOAD_ERROR: 8
}
arduino
{
INPUT: 1, // INPUT by the user
LIMBO: 2, // Restored from the server as a temporary file
LOCAL: 3 // 是本地服务器文件,已上传并确认不在服务器临时上传文件夹中的文件
};
文件信息 File Item
FileFond 实例的 addFile、getFile、processFile 方法,返回的都是 FileItem 对象。
请注意:FileItem 对象,是 FilePond 内部,对文件本身的二次封装定义,携带了与 FilePond 强相关的独特属性和方法!
Getters
Property | Description |
---|---|
id | 文件的 id |
serverId | 文件的 server id |
origin | 文件的 origin,有以下几种类型:1. input (由用户添加) |
- limbo(临时的服务器文件)
- local(现有的服务器文件) | | status | 文件的当前状态,由枚举 FilePond.FileStatus 来决定 | | file | 文件 File 对象 | | fileExtension | 文件的拓展类型 extension | | fileSize | 文件的大小 size | | filename | 文件的全名(含拓展类型 extension) | | filenameWithoutExtension | 不含拓展的文件名 |
Methods
Method | Description |
---|---|
abortLoad() | 中止加载该文件 |
abortProcessing() | 中止处理该文件 |
getMetadata(key?) | 按 key 检索保留在文件中的元数据,若没有 key,则返回完整的元数据 |
setMetadata(key, value) | 为文件添加额外的元数据 |
组件实例 Instance
每个 FilePond 实例,都有一些列方法、属性、和事件,使得在项目中的集成,变得很容易
属性 Properties
A list of properties to read from and write to the current state of FilePond.
The FilePond instance exposes a set of properties that enable us to update its state.
核心属性
FilePond 模块暴露了下面的核心属性
Property | Default Value | Description |
---|---|---|
element | null | 1. FilePond 实例的根元素 |
- 无 setter | | status | 0 | 1. FilePond 实例的状态
- 无 setter | | name | 'filepond' | 1. [ ] 标签的 name 属性
- 同时也作为 输入字段名称 | | className | null | 为 FilePond 实例的根元素,添加额外的 class 类名 |
filepond 使用示例
xml
<template>
<input ref="vue-filepond" type="file" />
</template>
<script>
import { create } from 'filepond'
import 'filepond/dist/filepond.min.css'
export default {
name: 'LargeFileUpload',
mounted() {
const el = this.$refs['vue-filepond'] // FilePond 根元素
this.filePond = create(el, {
name: 'File',
credits: [],
className: 'tf-vue-filepond-root'
}) // FilePond 实例
}
}
</script>
Property | Default Value | Description |
---|---|---|
required | false | 将输出字段设为必填 |
disabled | false | 将输出字段设为禁用 |
captureMethod | null | 设置 capture 属性 |
files | A list of file locations that should be loaded Immediately | 应立即加载的文件位置列表 |
allowRevert | true | 是否启用重试按钮the revert processing button ? |
allowRemove | true | |
allowProcess | true | |
allowReorder |
Server 类属性
Property | Default Value | Description |
---|---|---|
server | null | A server configuration object describing how FilePond should interact with the server. |
instantUpload | true | 是否将文件立即上传到服务器 |
chunkUploads | false | 启用分块上传,启后会在上传前自动将文件切成 chunkSize 块 |
chunkForce | false | 对于小于设置的 chunkSize 的文件也强制使用块 |
chunkSize | 5000000 | 块的大小(以字节为单位) |
chunkRetryDelays | [500,1000,3000] | 重新上传的延迟时间 |
Callbacks 类属性
Property | Function |
---|---|
oninit() | FilePond 实例已被创建,并已完成初始化 |
onwarning(error[, file, status]) | FilePond 抛出警告 |
onerror(error[, file, status]) | FilePond 抛出异常 |
oninitfile(file) | 已创建文件的 File Item |
Property | Function |
---|---|
onaddfilestart(file) | 已开始文件加载 Started file load |
onaddfileprogress(file, progress) | 加载文件取得进展 Made progress loading a file |
onaddfile(error, file) | 无报错时,表示文件已被成功加载 |
Hooks 类属性
Property | Description |
---|---|
beforeDropFile(file) | 拖拽文件前的钩子,返回 false 标识阻止拖拽(支持返回 boolean 或 promise) |
beforeAddFile(item) | 添加文件前的钩子,返回 false 表示阻止添加(支持返回 boolean 或 promise) |
beforeRemoveFile(item) | 删除文件前的钩子,返回 false 表示阻止删除(支持返回 boolean 或 promise) |