文件上传的传统形式,是使用表单元素 file
:
<input type="file" id="file-uploader" />
你可以添加 change
事件监听器读取 event.target.files
文件对象。
const fileUploader = document.getElementById('file-uploader')
fileUploader.addEventListener('change', (e) => {
const files = e.target.files
console.log('files', files)
})
使用 multiple
属性:
<input type="file" id="file-uploader" multiple />
在成功上传文件内容后,您可能需要显示该文件内容。对于图片,如果我们在上传后不立即将上传的图片显示给用户,则会感到困惑。
每当上传文件时,File
对象都会包含元数据信息,如文件名称、大小、上次更新时间、类型等。此信息可用于进一步验证和决策。
const fileUploader = document.getElementById('file-uploader')
// 监听更改事件并读取元数据
fileUploader.addEventListener('change', (e) => {
// 获取文件列表数组
const files = e.target.files
// 循环浏览文件并获取元数据
for (const file of files) {
const name = file.name
const type = file.type ? file.type : 'NA'
const size = file.size
const lastModified = file.lastModified
console.log({ file, name, type, size, lastModified })
}
})
我们准备一个上传文件控件,并为预览所选文件准备 img
元素,结构如下:
<input type="file" id="fileInput" />
<img id="preview" />
getElementById()
方法可以获取这两个元素:
const fileEle = document.getElementById('fileInput')
const previewEle = document.getElementById('preview')
URL.createObjectURL()
方法包含一个表示参数中给出的对象的 URL。这个新的 URL 对象表示指定的 File
对象或 Blob
对象。
fileEle.addEventListener('change', function (e) {
// 获取所选文件
const file = e.target.files[0]
// 创建引用该文件的新 URL
const url = URL.createObjectURL(file)
// 设置预览元素的源
previewEle.src = url
})
推荐:URL 对象
- 使用
FileReader
对象将文件转换为二进制字符串。然后添加load
事件监听器,以获得成功文件上传的二进制字符串。 FileReader.readAsDataURL()
方法用于读取指定的Blob
或File
对象。
// 获取 FileReader 的实例
const reader = new FileReader()
fileUploader.addEventListener('change', (e) => {
const files = e.target.files
const file = files[0]
// 上传后获取文件对象,以 URL 二进制字符串的形式读取数据
reader.readAsDataURL(file)
// 加载后,对字符串进行处理
reader.addEventListener('load', (e) => {
// 设置预览元素的源
previewEle.src = reader.result
})
})
使用 accept
属性来限制要上传的文件类型。
<input type="file" id="file-uploader" accept=".jpg, .png" multiple />
上面示例中,浏览器将只允许具有 .jpg
和 .png
的文件类型。
我们读取了文件的大小元数据,可以使用它进行文件大小验证。您可以允许用户上传高达 1MB 的图像文件。
// 文件上载更改事件的监听器
fileUploader.addEventListener('change', (event) => {
// 读取文件大小
const file = event.target.files[0]
const size = file.size
let msg = ''
// 检查文件大小是否大于 1MB,提示对应消息。
if (size > 1024 * 1024) {
msg = `<span style="color: red;">允许的文件大小为 1MB。您尝试上载的文件属于${returnFileSize(
size
)}</span>`
} else {
msg = `<span style="color: green;"> ${returnFileSize(
size
)} 文件已成功上载。 </span>`
}
// 向用户显示消息
feedback.innerHTML = msg
})
更好的可用性是让用户了解文件上传进度。XMLHttpRequest 第二版还定义了一个 progress
事件,可以用来制作进度条。
先在页面中放置一个 progress
标签
<label id="progress-label" for="progress" />
<progress id="progress" value="0" max="100" value="0">0</progress>
定义 progress
事件的回调函数
const reader = new FileReader()
reader.addEventListener('progress', (e) => {
if (e.loaded && e.total) {
// 计算完成百分比
const percent = (e.loaded / e.total) * 100
// 将值设置为进度组件
progress.value = percent
}
})
有一个非标准属性 webkitdirectory
,使我们能够上传整个目录。
虽然最初仅针对基于 WebKit 的浏览器实施,但 WebkitDirectory 在微软 Edge 以及 Firefox 50 及以后也可用。然而,即使它有相对广泛的支持,它仍然不是标准的,不应该使用,除非你别无选择。
<input type="file" id="file-uploader" webkitdirectory />
主要的 JS 如下:
const dropZone = document.getElementById('drop-zone')
const content = document.getElementById('content')
dropZone.addEventListener('dragover', (event) => {
event.stopPropagation()
event.preventDefault()
event.dataTransfer.dropEffect = 'copy'
})
dropZone.addEventListener('drop', (event) => {
// 获取文件
const files = event.dataTransfer.files
// ..
})
使用 URL.createObjectURL()
方法从文件创建一个唯一的 URL。使用 URL.revokeObjectURL()
方法释放它。
DOM 和
URL.createObjectURL()
和URL.revokeObjectURL()
方法允许您创建简单的 URL 字符串,可用于引用任何可以使用 DOM 文件对象引用的数据,包括用户计算机上的本地文件。
示例:
<div>
<h1>使用 Object URL</h1>
<input type="file" id="file-uploader" accept=".jpg, .jpeg, .png" />
<div id="image-grid"></div>
</div>
const fileUploader = document.getElementById('file-uploader')
const reader = new FileReader()
const imageGrid = document.getElementById('image-grid')
fileUploader.addEventListener('change', (event) => {
const files = event.target.files
const file = files[0]
const img = document.createElement('img')
imageGrid.appendChild(img)
img.src = URL.createObjectURL(file)
img.alt = file.name
})