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

Angular如何在新标签页打开已上传未入库的本地文件

Angular文件上传后点击新标签页打开实现方案

问题背景

当前已在Angular应用中实现基础文件上传功能,支持上传除.exe、.sql等少数禁用类型外的任意格式文件:

  • 初始前端模板代码:
<input type="file" id="file" #file (change)="fileUploadHandler($event)" multiple>
  • 初始文件上传处理逻辑(fileupload.component.ts):
fileUploadHandler(event: Event) {
const inputElement = event.target as HTMLInputElement;
if (inputElement.files && inputElement.files?.length) {
  _each(inputElement.files, (_file) => {
    const fileSize = _file.size;
    if (fileSize < this.MAX_DOC_SIZE) {
      const fileName = _file.name?.trim();
      const doc = new Document();
      doc.name = fileName;
      doc.extension = fileName.slice(fileName.lastIndexOf('.') + 1);
      doc.size = fileSize;
      this.docs.push(doc);
    } 
  });
}}

现有逻辑会将符合大小要求的文件信息解析后存入docs数组,在UI层渲染为文件列表,展示效果如下:
文件列表

待解决问题

需要实现交互效果:用户点击列表中的某一文件时,该文件直接在新标签页打开。
之前尝试使用FileReader编写的代码未生效,控制台无有效数据输出,问题代码如下:

_each(inputElement.files, (_file) => {
    const reader = new FileReader();
    const data = reader.readAsDataURL(_file);
    console.log(data) // 控制台无内容输出
})

问题原因

  • 原有doc数据结构仅存储了文件名、后缀、大小,未存储原始文件引用或可访问的文件地址,点击事件触发时无法获取文件源
  • FileReader.readAsDataURL是异步API,调用后不会同步返回结果,直接打印返回值拿不到读取到的内容,必须等待加载完成事件触发后才能从实例上获取结果
  • 对于文件预览打开场景,FileReader读取全量文件转base64的方案性能差,大文件下内存占用高,不是最优实现

实现步骤

1. 改造上传处理逻辑,生成文件临时访问地址

优先使用URL.createObjectURL生成Blob临时地址,相比FileReader方案性能更高、内存占用更小。改造后上传逻辑如下:

fileUploadHandler(event: Event) {
const inputElement = event.target as HTMLInputElement;
if (inputElement.files && inputElement.files?.length) {
  _each(inputElement.files, (_file) => {
    const fileSize = _file.size;
    if (fileSize < this.MAX_DOC_SIZE) {
      const fileName = _file.name?.trim();
      const doc = new Document();
      doc.name = fileName;
      doc.extension = fileName.slice(fileName.lastIndexOf('.') + 1);
      doc.size = fileSize;
      // 存储原始文件引用
      doc.rawFile = _file;
      // 生成同源临时访问地址
      doc.previewUrl = URL.createObjectURL(_file);
      this.docs.push(doc);
    } 
  });
}}

注意:需要先给Document类新增rawFile: File、previewUrl: string两个类型定义,避免TS类型报错。

2. 模板绑定列表项点击事件

在文件列表渲染位置,给每个文件项绑定点击触发方法,示例:

<div class="file-list">
  <div *ngFor="let doc of docs" class="file-item" (click)="openFileInNewTab(doc)">
    <span class="file-name">{{doc.name}}</span>
    <span class="file-size">{{doc.size | filesize}}</span>
  </div>
</div>

3. 实现新标签页打开方法

在组件类中新增打开方法,直接调用window.open打开之前生成的临时地址即可,浏览器会自动识别可预览格式(图片、PDF、纯文本等)在新标签页直接展示:

openFileInNewTab(doc: Document) {
  window.open(doc.previewUrl, '_blank');
}

4. 处理内存泄漏

在组件销毁生命周期中,释放所有生成的Blob临时地址,避免内存占用:

import { Component, OnDestroy } from '@angular/core';

export class FileuploadComponent implements OnDestroy {
  // ... 其他原有代码

  ngOnDestroy(): void {
    this.docs.forEach(doc => {
      if (doc.previewUrl) {
        URL.revokeObjectURL(doc.previewUrl);
      }
    })
  }
}

附:FileReader正确写法(不推荐,仅作参考)

如果一定要用FileReader实现,必须监听onload事件等待读取完成再拿结果:

_each(inputElement.files, (_file) => {
    const reader = new FileReader();
    reader.onload = () => {
      // 读取完成后才能拿到base64结果
      const data = reader.result;
      console.log(data);
      // 此处将data赋值给doc的预览地址字段即可
    }
    reader.readAsDataURL(_file);
})

内容的提问来源于stack exchange,提问作者Kgn-web

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:57:12