You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular+PrimeNG文件上传选中文件无法清除及优化需求

问题根源分析

  1. 文件选择残留:点击取消按钮时仅调用了fileUpload.clear(),但未清空存储文件的base64DataArray和uploadedFiles数组;且onSelect事件每次触发都会追加文件到数组,导致旧文件残留重复上传,最终触发413请求体过大错误。
  2. 大文件适配问题:将文件转成base64会让体积膨胀约30%,既占用大量客户端内存,又极易触发后端的请求体限制,这种方式仅适合小文件场景。

解决方案

1. 修复文件清除与重复选择问题

  • 绑定fileUpload的onCancel事件,触发时彻底清空所有文件数组和组件状态
  • onSelect触发时先清空旧数组,避免追加重复文件
  • 上传成功/失败后统一重置相关数组和组件状态

2. 优化大文件上传逻辑

  • 放弃base64转码,改用FormData直接上传文件,避免体积膨胀和内存占用问题
  • 调整服务调用逻辑,适配FormData格式传递

修改后的代码

component.ts

import { Component, ViewChild } from '@angular/core';
import { FileUpload } from 'primeng/fileupload';

uploadedFiles: any[] = [];
base64DataArray: any[] = [];
@ViewChild('fileUpload') fileUpload: FileUpload;

getTokenUpload(user: string, ci: string) {
  this.service.getToken(environment.SCOPES["carga"]).subscribe(
    (data: any) => {
      const token = data.access_token;
      this.onUploadWithFormData(user, ci, token);
      this.resetFileUpload();
    },
    (error) => {
      console.error('获取token失败: ', error);
      this.resetFileUpload();
    }
  );
}

onUploadWithFormData(user: string, ci: string, token: string) {
  this.blockUI.start("上传中...");
  const formData = new FormData();
  formData.append('user', user);
  formData.append('ci', ci);
  
  this.fileUpload.files.forEach(file => {
    formData.append('files[]', file, file.name);
  });

  this.service.uploadFilesWithFormData(formData, token).subscribe(
    () => {
      this.showUploadFiles = false;
      this.blockUI.stop();
      this.showMessage('success', '成功', '文件上传完成');
      this.getToken();
      this.resetFileUpload();
    },
    (error) => {
      console.error('上传失败: ', error);
      this.showMessage('error', '上传失败', '文件上传出现错误');
      this.blockUI.stop();
      this.resetFileUpload();
    }
  );
}

onFileSelected(event: any): void {
  this.uploadedFiles = [];
  this.base64DataArray = [];
  
  const files = event.files;
  if (files && files.length > 0) {
    this.uploadedFiles = files.map(file => ({name: file.name, size: file.size}));
    // 若仍需处理小文件base64,可保留下方代码
    // this.convertToBase64Array(files);
  }
}

resetFileUpload(): void {
  if (this.fileUpload) {
    this.fileUpload.clear();
  }
  this.uploadedFiles = [];
  this.base64DataArray = [];
}

convertToBase64Array(files: File[]): void {
  for (const file of files) {
    const reader = new FileReader();
    reader.onload = (e: any) => {
      let base64Data = e.target.result;
      base64Data = this.getBase64WithoutPrefix(base64Data);
      this.base64DataArray.push({ filename: file.name, file: base64Data });
    };
    reader.readAsDataURL(file);
  }
}

getBase64WithoutPrefix(base64Data: string): string {
  return base64Data.replace(/^data:[^;]+;base64,/, '');
}

HTML代码

<p-dialog [(visible)]="showUploadFiles" [style]="{width: '1050px'}" header="选择文件"
          [modal]="true" styleClass="p-fluid" [resizable]="true">

  <p-fileUpload #fileUpload
                name="files[]"
                (onBeforeUpload)="getTokenUpload(user, ci)"
                (onSelect)="onFileSelected($event)"
                (onCancel)="resetFileUpload()"
                [multiple]="true"
                accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.rar,.webp"
                maxFileSize="187286400"
                chooseLabel="选择文件" uploadLabel="上传" cancelLabel="取消">

    <ng-template pTemplate="content">
      <ul *ngIf="uploadedFiles.length">
        <li *ngFor="let file of uploadedFiles">{{ file.name }} - {{ file.size }} bytes</li>
      </ul>
    </ng-template>
  </p-fileUpload>
</p-dialog>

服务端调用调整(service.ts示例)

uploadFilesWithFormData(formData: FormData, token: string): Observable<any> {
  const headers = new HttpHeaders({
    'Authorization': `Bearer ${token}`
  });
  return this.http.post(`${environment.apiUrl}/upload`, formData, { headers });
}

关键说明

  • 状态统一重置:通过resetFileUpload()方法集中处理组件和数组的清空逻辑,确保取消、成功、失败场景下都能彻底清除旧文件
  • 大文件适配:FormData是浏览器原生支持的文件上传方式,不会增加文件体积,后端只需按multipart/form-data格式接收即可
  • 类型安全优化:将fileUpload的类型从any改为FileUpload,避免潜在的类型错误

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:40:32