Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Xóa mục khỏi FileList của input multiple file trong HTML5

Đối tượng FileList (trả về bởi input.files) là read-only (chỉ đọc) và bất biến (immutable). Không thể xóa trực tiếp phần tử khỏi FileList bằng JavaScript.

Giải pháp: Chuyển sang Array -> Xử lý -> Gán lại (nếu cần)

Cách 1: Tạo Array mới từ FileList, lọc, dùng Array đó

const fileInput = document.querySelector('input[type="file"][multiple]');
const filesArray = Array.from(fileInput.files); // Chuyển FileList -> Array

// Lọc: ví dụ xóa file index 1, hoặc lọc theo size/name
const filteredFiles = filesArray.filter((file, index) => index !== 1); // Xóa item index 1
// Hoặc: filteredFiles = filesArray.filter(f => f.size < 5*1024*1024); // < 5MB

// Sử dụng filteredFiles cho FormData, upload, hiển thị preview...
const formData = new FormData();
filteredFiles.forEach(file => formData.append("files[]", file));

Cách 2: DataTransfer API (Tạo FileList mới) - Để gán lại vào input.files

Nếu bắt buộc phải gán FileList mới vào input.files (ví dụ: hiển thị lại cho user, submit form gốc), dùng DataTransfer (hỗ trợ tốt trên Chrome, Edge, Firefox mới; Safari hạn chế).

const fileInput = document.querySelector('input[type="file"][multiple]');
const dt = new DataTransfer(); // Tạo DataTransfer rỗng

// Lọc file từ FileList gốc
Array.from(fileInput.files).forEach((file, index) => {
    if (index !== 1) { // Giữ lại trừ index 1
        dt.items.add(file); // Thêm file vào DataTransfer
    }
});

// Gán FileList MỚI vào input (Chỉ hoạt động trên trình duyệt hiện đại, KHÔNG phải mọi nơi)
fileInput.files = dt.files; 

// Lưu ý: fileInput.files = dt.files KHÔNG hoạt động trên Safari, một số mobile browser.
// Cách an toàn: Dùng FormData từ filteredFiles để submit qua AJAX/Fetch.

Cách 3: Quản lý state riêng (React/Vue/Angular/Vanilla State) - Best Practice

Không phụ thuộc vào input.files. Lưu danh sách file đã chọn trong state (Array), render UI từ state, xóa từ state, submit từ state.

// Vanilla JS State Pattern
let selectedFiles = []; // State quản lý file

fileInput.addEventListener("change", (e) => {
    selectedFiles = Array.from(e.target.files); // Cập nhật state
    renderFileList(); // Render UI từ state
});

function removeFile(index) {
    selectedFiles.splice(index, 1); // Xóa khỏi state
    renderFileList(); // Cập nhật UI
}

function submitFiles() {
    const formData = new FormData();
    selectedFiles.forEach(f => formData.append("files[]", f));
    fetch("/upload", { method: "POST", body: formData });
}

Tóm tắt

CáchƯu điểmNhược điểmPhù hợp
Array.from(files).filter(...)Đơn giản, an toàn, mọi trình duyệtKhông gán lại được input.filesXử lý, preview, upload qua FormData/Fetch
DataTransfer + input.files = dt.filesCập nhật input.files thậtKhông hỗ trợ Safari, một số mobile; phức tạpCần submit form gốc (non-AJAX)
Quản lý State riêng (Array)Kiểm soát hoàn toàn, framework-friendly, tách UI/logicViết code nhiều hơnBest Practice cho App thực tế

Kết luận: FileList bất biến. Hãy chuyển sang Array (Array.from(input.files)), lọc/sửa trên Array, sau đó dùng Array đó để tạo FormData upload (AJAX/Fetch) hoặc render UI. Tránh gán lại input.files do hỗ trợ trình duyệt không đồng đều.