如何用Vanilla.js结合表单与XMLHttpRequest异步上传文件(按钮在表单外)
Hey there! I’ve got a straightforward vanilla JS solution that matches your requirements perfectly—no frameworks needed, just plain JS using FormData like you planned. Here’s how to make it work smoothly:
Step 1: Your Existing HTML (With Minor Cleanup)
First, here’s your original HTML structure, formatted for clarity:
<form id="fileUploadForm" action="fileUpload.php" method="post" enctype="multipart/form-data"> <input type="file" name="fileToUpload" id="fileToUpload"> </form> <button id="btnUpload">Upload</button>
Step 2: The Vanilla JS Upload Logic
We’ll listen for clicks on the external button, validate a file is selected, package the form data with FormData, and send the request using the modern Fetch API (with an XHR fallback for older browsers included).
Modern Fetch API Approach (Recommended)
// Grab references to our DOM elements const uploadForm = document.getElementById('fileUploadForm'); const uploadButton = document.getElementById('btnUpload'); const fileInput = document.getElementById('fileToUpload'); // Add click handler to the external upload button uploadButton.addEventListener('click', async (e) => { e.preventDefault(); // Stop the button from triggering a page reload // First, check if a file was actually selected if (!fileInput.files.length) { alert('Whoops! Please select a file before clicking upload.'); return; } try { // Create a FormData object directly from the form element // This automatically captures all form fields (including the file) const formData = new FormData(uploadForm); // Send the request using Fetch const response = await fetch(uploadForm.action, { method: uploadForm.method, // Reuse the form's method (POST) body: formData // Pass our FormData as the request body }); // Handle the server's response if (response.ok) { const serverResponse = await response.text(); // Use response.json() if your PHP returns JSON alert(`Upload successful! 🎉\nServer said: ${serverResponse}`); uploadForm.reset(); // Optional: Reset the form after success } else { throw new Error(`Server error: ${response.status} ${response.statusText}`); } } catch (error) { console.error('Upload failed:', error); alert('Upload failed—check the browser console for details.'); } });
Older Browser Fallback (XMLHttpRequest)
If you need to support browsers that don’t have Fetch (like IE11), use this XHR version instead:
const uploadForm = document.getElementById('fileUploadForm'); const uploadButton = document.getElementById('btnUpload'); const fileInput = document.getElementById('fileToUpload'); uploadButton.addEventListener('click', (e) => { e.preventDefault(); if (!fileInput.files.length) { alert('Please select a file first!'); return; } const formData = new FormData(uploadForm); const xhr = new XMLHttpRequest(); xhr.open(uploadForm.method, uploadForm.action); // Listen for when the request completes xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { alert(`Upload successful!\nServer said: ${xhr.responseText}`); uploadForm.reset(); } else { alert(`Upload failed. Server status: ${xhr.status}`); } }; // Handle network errors xhr.onerror = function() { alert('A network error occurred while uploading.'); }; // Send the request xhr.send(formData); });
Step 3: Quick Note for Your PHP Backend
Make sure your fileUpload.php handles the file correctly. Here’s a basic working example (add validation for file type/size in production!):
<?php // Define where to store uploaded files $targetDirectory = "uploads/"; $targetFile = $targetDirectory . basename($_FILES["fileToUpload"]["name"]); // Create the uploads directory if it doesn't exist if (!file_exists($targetDirectory)) { mkdir($targetDirectory, 0755, true); } // Try to move the uploaded file to the target directory if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) { echo "Success! File uploaded as: " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"])); } else { echo "Error: Could not upload your file."; } ?>
Important: Set proper permissions on the
uploadsdirectory (usually755for most servers) and add checks for file size, allowed types, and duplicate filenames before deploying to production.
内容的提问来源于stack exchange,提问作者Black

