使用 HTML 和 JavaScript 实现文件上传功能
1. 简介
在现代 web 开发中,实现文件上传功能是一个常见的需求。本文将介绍如何使用 HTML、CSS 和 JavaScript 创建一个支持 .obj
和 .jpg
文件上传的网页应用,并且展示上传进度以及上传完成后的文件信息。用户可以逐个选择文件并上传,最后将上传成功的文件信息通过 JSON 发送到服务器。页面效果:
2. 开发环境
- HTML5
- CSS3
- JavaScript (ES6)
3. 对话过程
我们从基础的文件上传功能开始,逐步改进页面的用户界面和功能,实现选择文件、显示进度、上传文件、展示上传结果等功能。以下是最终的 HTML、CSS 和 JavaScript 代码。
HTML 文件 (index.html)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="uploadContainer">
<label for="fileInput">选择文件:</label>
<input type="file" id="fileInput" multiple>
<button id="uploadButton">上传文件</button>
<div id="progressWrapper"></div>
<div id="response">
<h2>错误信息</h2>
</div>
<table id="fileTable">
<thead>
<tr>
<th>文件名</th>
<th>文件类型</th>
<th>文件编号</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script src="upload.js"></script>
</body>
</html>
CSS 文件 (styles.css)
body {
font-family: Arial, sans-serif;
margin: 20px;
}
#uploadContainer {
margin-bottom: 20px;
}
label, button {
display: block;
margin-top: 10px;
}
#progressWrapper {
width: 100%;
background: #f3f3f3;
border: 1px solid #ccc;
height: 20px;
position: relative;
margin-top: 10px;
}
.progressBar {
height: 100%;
background: green;
text-align: center;
color: white;
line-height: 20px;
}
#fileTable {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
#fileTable th, #fileTable td {
border: 1px solid #ccc;
padding: 10px;
text-align: left;
}
#error {
color: red;
}
JavaScript 文件 (upload.js)
document.addEventListener('DOMContentLoaded', () => {
const fileInput = document.getElementById('fileInput');
const uploadButton = document.getElementById('uploadButton');
const progressWrapper = document.getElementById('progressWrapper');
const responseDiv = document.getElementById('response');
const fileTableBody = document.querySelector('#fileTable tbody');
let selectedFiles = [];
fileInput.addEventListener('change', (event) => {
selectedFiles = Array.from(event.target.files);
displayProgressBars();
});
uploadButton.addEventListener('click', () => {
if (selectedFiles.length === 0) {
alert('请先选择文件');
return;
}
uploadFiles();
});
function displayProgressBars() {
progressWrapper.innerHTML = '';
selectedFiles.forEach((file, index) => {
const progressBar = document.createElement('div');
progressBar.className = 'progressBar';
progressBar.id = `progress_${index}`;
progressBar.style.width = '0%';
progressBar.innerText = `${file.name} - 0%`;
progressWrapper.appendChild(progressBar);
});
}
async function uploadFiles() {
for (let i = 0; i < selectedFiles.length; i++) {
await uploadFile(selectedFiles[i], i);
}
sendJsonArray();
selectedFiles = [];
fileInput.value = '';
}
function uploadFile(file, index) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
xhr.upload.addEventListener('progress', (event) => {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
const progressBar = document.getElementById(`progress_${index}`);
progressBar.style.width = `${percentComplete}%`;
progressBar.innerText = `${file.name} - ${Math.round(percentComplete)}%`;
}
});
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
const fileType = file.name.endsWith('.jpg') ? 11 : 0;
const fileData = {
fileNo: response.data,
fileType: fileType
};
addFileToTable(file.name, fileType, response.data);
localStorage.setItem(`file_${index}`, JSON.stringify(fileData));
resolve();
} else {
responseDiv.innerText = `Error uploading ${file.name}: ${xhr.responseText}`;
reject();
}
}
};
xhr.open('POST', 'http://192.168.0.188:8098/VR-Editor/resource/upload');
xhr.setRequestHeader('ContentType', 'multipart/form-data');
xhr.send(formData);
});
}
function sendJsonArray() {
const fileList = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith('file_')) {
fileList.push(JSON.parse(localStorage.getItem(key)));
}
}
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://192.168.0.188:8098/VR-Editor/file-edit/file-edit', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
console.log('JSON array sent successfully');
localStorage.clear();
clearTable();
} else {
responseDiv.innerText = `Error sending JSON array: ${xhr.responseText}`;
}
}
};
xhr.send(JSON.stringify(fileList));
}
function addFileToTable(fileName, fileType, fileNo) {
const row = document.createElement('tr');
row.innerHTML = `<td>${fileName}</td><td>${fileType}</td><td>${fileNo}</td>`;
fileTableBody.appendChild(row);
}
function clearTable() {
fileTableBody.innerHTML = '';
}
});
4. 总结
通过本文的示例代码,我们学习了如何使用 HTML、CSS 和 JavaScript 创建一个支持多文件上传的网页应用。我们实现了选择文件、显示上传进度、上传文件并展示上传结果等功能。最终,我们将上传成功的文件信息保存到本地存储,并在上传完成后发送到服务器。希望本文对您理解和实现文件上传功能有所帮助。