You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用FormData与jQuery Ajax上传多文件时遇到问题

Hey there, let's work through your problem step by step. That Uncaught TypeError: Illegal invocation error is a super common gotcha when using jQuery Ajax with FormData, so let's start with fixing that core issue first, then tackle the image preview, removal, and reordering logic.

1. Fix the "Illegal Invocation" Error (Root Cause)

This error happens because jQuery automatically tries to serialize any data you pass to its ajax() method—but FormData is a native browser object that can't be processed by jQuery's default serialization logic. To fix this, you need to add two critical settings to your Ajax configuration:

  • processData: false: Tells jQuery not to convert your FormData object to a string; pass it directly to the browser's XMLHttpRequest.
  • contentType: false: Lets the browser automatically set the correct multipart/form-data Content-Type header (including the boundary separator required for file uploads).

Here's a corrected Ajax example:

$('#your-form').on('submit', function(e) {
  e.preventDefault(); // Prevent default form submission
  const formData = new FormData(this); // Pull form data (including files) directly from the form

  $.ajax({
    url: '/your-server-upload-endpoint',
    method: 'POST',
    data: formData,
    processData: false, // Required for FormData
    contentType: false, // Required for FormData
    success: function(response) {
      console.log('Upload successful!', response);
    },
    error: function(xhr, status, err) {
      console.error('Upload failed:', err);
    }
  });
});
2. Handling Image Preview, Removal & Reordering

For your image management features, you'll need to track selected files separately (instead of relying solely on the form's file input) to handle dynamic changes like removal and reordering. Here's how to approach each part:

2.1 Image Preview

Use the FileReader API to generate previews when users select images:

// Track selected files in an array for easy manipulation
let selectedFiles = [];

$('input[type="file"]').on('change', function(e) {
  const newFiles = Array.from(e.target.files);
  selectedFiles = [...selectedFiles, ...newFiles];

  // Generate previews for each new file
  newFiles.forEach((file, index) => {
    if (!file.type.match('image.*')) return; // Skip non-image files

    const reader = new FileReader();
    reader.onload = function(event) {
      // Create a preview container with image and remove button
      const previewItem = $('<div>').addClass('preview-item');
      const previewImg = $('<img>').attr('src', event.target.result).addClass('preview-img');
      const removeBtn = $('<button>').text('Remove').data('file-index', selectedFiles.length - 1);

      previewItem.append(previewImg, removeBtn);
      $('#preview-container').append(previewItem);
    };
    reader.readAsDataURL(file);
  });
});

2.2 Removing Images

Since FormData doesn't have a straightforward way to delete specific files, updating our selectedFiles array and rebuilding FormData on upload is the most reliable approach:

// Handle remove button clicks with event delegation
$('#preview-container').on('click', 'button', function() {
  const fileIndex = $(this).data('file-index');
  // Remove the file from our tracking array
  selectedFiles.splice(fileIndex, 1);
  // Remove the preview element from the DOM
  $(this).closest('.preview-item').remove();

  // Update the index data on remaining remove buttons to avoid mismatches
  $('.preview-item').each((i, el) => {
    $(el).find('button').data('file-index', i);
  });
});

2.3 Reordering Images

If you want drag-and-drop reordering, use a library like jQuery UI Sortable (or a lightweight alternative) to update the selectedFiles array when the user reorders previews:

// Initialize sortable preview container (requires jQuery UI)
$('#preview-container').sortable({
  update: function(event, ui) {
    // Rebuild the selectedFiles array to match the new preview order
    const reorderedFiles = [];
    $('.preview-item').each((i, el) => {
      const originalIndex = $(el).find('button').data('file-index');
      reorderedFiles.push(selectedFiles[originalIndex]);
    });
    selectedFiles = reorderedFiles;

    // Update index data on all remove buttons
    $('.preview-item').each((i, el) => {
      $(el).find('button').data('file-index', i);
    });
  }
});
3. Final Upload with Updated Files

When you're ready to upload (after preview, removal, or reordering), rebuild the FormData from your selectedFiles array:

function uploadUpdatedFiles() {
  const formData = new FormData();
  // Add each file to FormData (use a name like `images[]` for multiple files)
  selectedFiles.forEach((file, index) => {
    formData.append('images[]', file, file.name);
  });

  // Send the Ajax request (don't forget the two critical settings!)
  $.ajax({
    url: '/your-server-upload-endpoint',
    method: 'POST',
    data: formData,
    processData: false,
    contentType: false,
    success: function(response) {
      console.log('Updated files uploaded successfully!', response);
    },
    error: function(xhr, status, err) {
      console.error('Upload failed:', err);
    }
  });
}
Quick Additional Checks
  • Make sure your file input has a name attribute (e.g., <input type="file" name="images[]" multiple>)—servers use this to access uploaded files.
  • If you're adding file inputs dynamically, use event delegation (like $(document).on('change', '.dynamic-file-input', function() { ... })) to bind change events.
  • Verify your server is configured to accept multipart/form-data requests (e.g., PHP uses $_FILES, Node.js uses middleware like multer).

内容的提问来源于stack exchange,提问作者JJ BOBO

火山引擎 最新活动