如何实现文件上传和预览?

文件上传是Web应用中的常见功能,通常涉及前端选择文件、本地预览,以及后端接收并存储文件。现代JavaScript API让这个过程变得比以往更直观。

前端选择与读取文件

核心是利用<input type="file">元素,它允许用户从设备中选择文件。通过监听其change事件,我们可以获取到用户选择的文件列表(FileList对象)。

<input type="file" id="fileInput" accept="image/*">
<img id="preview" src="#" alt="预览" style="display:none; max-width: 300px;">
const fileInput = document.getElementById('fileInput');
const preview = document.getElementById('preview');

fileInput.addEventListener('change', function(e) {
  const file = e.target.files[0];
  if (!file) return;

  // 创建文件预览
  const reader = new FileReader();
  reader.onload = function(event) {
    preview.src = event.target.result;
    preview.style.display = 'block';
  };
  reader.readAsDataURL(file); // 将文件读取为Data URL
});

FileReader对象可以异步读取文件内容。readAsDataURL方法将文件转换为Base64编码的URL,非常适合用于在<img>标签中直接预览图片。对于其他文件类型(如PDF),预览逻辑会更复杂。

使用FormData进行文件上传

将文件发送到服务器的最标准方式是使用FormData对象。它可以模拟表单提交,非常适合传输文件数据。

async function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file); // 'file'是服务器期望的字段名
  formData.append('userId', '123'); // 可以附加其他数据

  try {
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData
      // 注意:不要手动设置 Content-Type,浏览器会自动添加正确的 multipart/form-data 边界
    });
    const result = await response.json();
    console.log('上传成功', result);
  } catch (error) {
    console.error('上传失败', error);
  }
}

// 在文件选择后调用
fileInput.addEventListener('change', (e) => {
  const file = e.target.files[0];
  if (file) {
    uploadFile(file);
  }
});

使用FormData时,无需手动设置请求头Content-Type,浏览器会自动处理。这是上传二进制文件(如图片、视频)的推荐方式。

实现拖拽上传

提升用户体验的一个方法是支持拖拽。通过监听容器的dragoverdragleavedrop事件可以实现。

<div id="dropZone" style="border: 2px dashed #ccc; padding: 50px; text-align: center;">
  将文件拖拽到此区域
</div>
const dropZone = document.getElementById('dropZone');
dropZone.addEventListener('dragover', (e) => {
  e.preventDefault();
  dropZone.style.borderColor = 'blue';
});
dropZone.addEventListener('dragleave', () => {
  dropZone.style.borderColor = '#ccc';
});
dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  dropZone.style.borderColor = '#ccc';
  const file = e.dataTransfer.files[0];
  if (file) {
    previewFile(file);
    uploadFile(file);
  }
});

drop事件中,通过e.dataTransfer.files可以获取到拖放的文件列表。

后端需要相应的API来接收multipart/form-data格式的数据(例如使用Node.js的multer中间件或Python的Flask框架)。对于大文件,还需要考虑分片上传和进度跟踪。前端通过XMLHttpRequestfetch的响应可以获取上传进度,为用户提供反馈。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容