记录一个常见的前端场景:给用户一个文件选择器,点击后能够从用户本地计算机抉择图片,也能够拖动图片至指定地位。并可显示图片预览,而后上传数据。
1. input 元素
input html 解说
应用 type=’file’ 的 <input> 元素,容许用户从他们的设施中抉择一个或多个文件
例子:
<input type="file"
id="avatar"
multiple={false}
accept="image/png, image/jpeg"
>
属性
- multiple:布尔值,是否容许抉择多个文件
- accept:字符串,能够承受的文件类型
无论用户的设施或操作系统是什么,文件输出都提供一个按钮,关上一个容许用户抉择文件的文件抉择对话框。
办法
当用户抉择了一个文件后,如何获取到 input 元素拿到的文件呢?
<input type="file"
onChange={handleFileChange}
>
const handleFileChange = (e) => {const files = e.target.files}
- 定义 input 元素的 onChange 事件:通过 event 对象,拿到用户抉择的文件列表:e.target.files
它是蕴含一系列 File 对象的 FileList 对象。FileList 的行为像一个数组,能够通过查看 length 属性来取得已抉择文件的数量。
每个 File 对象蕴含以下属性:
{
name: "编组 3.png" // 文件名
size: 1629 // 文件大小
type: "image/png" // 文件类型
lastModified: 1660545147281 // 文件最新批改工夫 工夫戳
}
- Blob 对象:Blob 对象示意一个不可变、原始数据的类文件对象。它的数据能够按文本或二进制的格局进行读取,也能够转换成 ReadableStream 来用于数据操作。
- File 对象:通常状况下,File 对象是来自用户在一个 <input> 元素上抉择文件后返回的 FileList 对象,也能够是来自在拖放操作生成的 DataTransfer 对象。
File 对象是非凡类型的 Blob。File 接口基于 Blob,继承了 blob 的性能并将其扩大以反对用户零碎上的文件。
自定义关上文件选择器的入口
默认款式
<input type='file' />
如果只是单纯的一个 input 元素,会渲染成默认的一个文件选择器的按钮:
为了好看,大部分状况须要暗藏这个‘抉择文件’按钮,自定义一个入口,比方对于抉择图片或视频
自定义
<div className={style.wrapper} onClick={click}>
<input type='file' ref={inputRef} className={style.input}/>
<div className={style.add} >
<Icon svg={IconAdd} className={style.addIcon} />
</div>
</div>
.input {display: none;}
const inputRef = useRef(null)
const click = () => {inputRef.current && inputRef.current.click()
}
- 将 input 元素款式 display:none, 暗藏 input 元素
- 点击父元素的事件处理器,调用 input 元素的 click 办法
成果:点击这个区域,就会关上文件选择器。
2. 显示被抉择图片的缩略图
常常会有如下场景:用户点击上图 + 范畴后,呈现文件选择器 – 用户抉择了一张图片 – 该图片缩略图展现在页面上。(展现的缩略图能够是任意尺寸,可自定义)
其实就是如何将一个图片文件 转换成 img 元素的 src,用于展现的问题。
咱们目前已知,从 input 元素拿到的图片文件是一个 File 对象,它会蕴含文件名等信息。那么该如何从中失去可用于 <img/>
元素的 src 属性呢?
有以下两种办法:
2.1 FileReader 读取文件内容
FileReader:
- FileReader 对象容许 Web 应用程序 异步读取 存储在用户计算机上的文件(或原始数据缓冲区)的内容。
- 应用 File 或 Blob 对象指定要读取的文件或数据。
- File 对象能够来自用户在一个 <input> 元素上抉择文件后返回的 FileList 对象,也能够来自拖放操作生成的 DataTransfer 对象
用法:const reader = new window.FileReader()
失去一个 fileReader 对象
reader.result
一个属性,只读,示意读取到的文件内容。留神,该属性只在读取操作实现后才无效。读取失去的数据格式 取决于应用什么办法启动的读取操作。
reader.readAsDataURL(blob)
开始读取指定的 Blob 或 File 对象,当读取操作实现,result 属性中将蕴含一个 data: URL 格局的 Base64 字符串以示意所读取文件的内容。当咱们想在 src 中应用此数据,并将其用于 img 或其余标签时, 能够用此办法。
// load 事件,读取操作实现时触发。可在该处理函数中拿到读取后果 reader.result
reader.addEventListener('load', () => {console.log('加载实现')
})
例子:
const [readFile, setReadFile] = useState(null)
const handleFileChange = (e) => {
const files = e.target.files
const file = files[0]
const reader = new window.FileReader()
reader.readAsDataURL(file)
reader.addEventListener('load', () => {
const result = reader.result
setReadFile(result)
})
}
return(readFile && <img src={readFile} />
)
- handleFileChange 是 input 元素的 onChange 事件处理器
- 拿到文件列表,以第一个文件为例,创立一个 reader 读取器,并监听 load 事件,当读取实现,将后果作为 img 元素的 src。而后以 URL 的格局开始读取
- 后果就是,当文件读取实现,readFile 就会有值,页面上就会呈现预览图片
file 和 fileReader
2.2 应用对象 URL 援用文件对象
URL.createObjectURL()
用法:
const url = window.URL.createObjectURL(file)
作用:
创立一个 URL 字符串,该字符串可能援用任何数据。也能够援用用户本地计算机的文件 File 对象。
因而应用对象 URL 也能够显示图片,只有将失去的 url 对象赋给 img.src 属性即可。
下图是打印出的 file 对象,和失去的对象 URL。
3. 上传文件到服务器
在显示用户所抉择的文件缩略图后,如果有将图片上传到服务器的须要,就须要发送 http 申请。
发送 http 申请能够用 XMLHttpRequest 或者 fetch API
3.1 XMLHttpRequest
XMLHttpRequest
在应用 XMLHttpRequest 发送文件数据时,个别先用 FormData 对象对图片文件做解决。
FormData 对象用来将数据编译成 键值对,以便用 XMLHttpRequest 来发送数据。
FormData
以图片为例:
const data = new window.FormData()
data.append('file', file) // file 就是一个 file 对象
const xhr = new XMLHttpRequest()
...
xhr.send(data)
参考链接:
全流程