网站首页 > 技术文章 正文
需求背景
不管是什么类型的项目,文件上传都是一个常见的功能。因此,在项目中我们经常需要使用上传组件。通过直接使用组件,可以减少我们的开发量,本文主要介绍上传组件的开发方式。
模块设计
按照需求分析,我们至少需要实现一个基本的上传流程:点击按钮-用户选择文件-完成上传。当然,作为一个高可用的组件,它需要具备更多的能力。如下:
- 支持上传文件列表的显示:包含文件名称、状态、删除按钮、上传进度,以及更多可能的功能支持
- 可自定义模板:需要能够自定义上传组件的样式
- 拖拽上传支持
- 支持一系列生命周期钩子事件:beforeUpload、onProgress、onSuccess、onError、onChange
- 自定义headers
- 自定义file的表单名称
- 自定义上传的数据
- 可接受的文件类型
- 限制图片规格
核心技术原理
上传文件有两种方式,传统模式使用form表单提交
<form method="post" action="#" enctype="multipart/form-data">
<input type="file" />
<button type="submit">Submit</button>
</form>
表单中enctype默认值为application/x-www-form-urlencoded,如果要有二进制数据需要设置为multipart/form-data。
另外,我们还可以使用ajax模式做异步提交。从input获得Files,涉及知识点:
- 事件参数e.target.files是FileList对象,它是一个类数组对象,不是真正的数组
- 通过files[索引]拿到对应的文件,它是一个File对象
- FormData是针对XHR2设计的数据结构,我们可以使用它模拟HTML的<form/>
拖拽上传实现方式
如图所示,我们要实现的点有:
- dragover和dragleave添加或者删除对应的class
- drop事件拿到正在被拖拽的文件,删除class并且触发上传
需要注意拖拽上传对于组件来说是可选的,只有在属性drag为true的时候才会生效。
知识点:DataTransfer对象用于保存拖动并放下(drag and drop)过程中的数据,它可以保存一项或多项数据,这种数据项可以是一种或多种数据类型。
drop事件触发时,判断dataTransfer是否存在,存在则表示有对应的文件,通过e.dataTransfer.files获得File对象。
本地图片预览方式
本地图片预览可以在图片上传完成之前显示图片,利用两个API:
- URL.createObjectURL()
- FileReader.readAsDataURL()
两种方式主要区别:
FileReader.readAsDataURL(file) | URL.createObjectURL(file) | |
返回值 | 可以得到一段base64的字符串 | 可以得到当前文件的一个内存URl |
执行机制 | 通过回调的形式返回,异步执行 | 直接返回,同步执行 |
内存清理 | 依照JS垃圾回收机制自动从内存中清理 | 存在于当前document内,清除方式只有unload()事件或revokeObjectURL()手动清除 |
如何选择:
- URL.createObjectURL(file)得到本地内存容器的URL地址,同步使用,比较方便快捷,多次使用需要注意手动释放内存的问题,性能优秀
- FileReader.readAsDataURL(file)胜在直接转为base64格式,可以直接用于业务,无需二次转换格式。
生命周期钩子实现
通过判断对应钩子事件是否存在,存在则执行
beforUpload && beforeUpload()
获取原始图片的大小
要限制图片的规格,我们需要在上传之前利用Image构造函数获取原始图片的宽高
export const getImageDimensions = (url: string | File) => {
return new Promise<{ width: number; height: number }>((resolve, reject) => {
const img = new Image();
img.src = typeof url === "string" ? url : URL.createObjectURL(url);
img.addEventListener("load", () => {
const { naturalWidth: width, naturalHeight: height } = img;
resolve({
width,
height,
});
});
img.addEventListener("error", () => {
reject(new Error("There was some proplem with the image."));
});
});
};
需要注意的是当我们传给函数的是一个File对象时,可以直接使用URL.createObjectURL(url)得到img的src。然后通过load事件监听获取原始宽高。
猜你喜欢
- 2024-11-13 JS二进制:Blob、File、FileReader、ArrayBuffer、Base64
- 2024-11-13 实现HTML5网站中常见的拖拽上传文件
- 2024-11-13 input上传图片并压缩(vue,前端,js)
- 2024-11-13 怎样用Nodejs,Express和FFmpeg.wasm构建一个处理多媒体的API
- 2024-11-13 为什么 JS 开发者更喜欢 Axios 而不是 Fetch?
- 2024-11-13 leaflet地图截图批量导出 leaflet 底图
- 2024-11-13 拖拽外部文件进行读取-FileReader
- 2024-11-13 JavaScript `FileReader` 接口提供的文件处理方法
- 2024-11-13 vue手把手教学~搭建web聊天室 vue实现聊天功能
- 2024-11-13 Html5 上传图片 移动端、PC端通用
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-