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

Angular5绑定错误:Cannot read property 'size' of undefined 求助

解决Angular中TypeScript值绑定HTML时的"Cannot read property 'size' of undefined"错误

嗨,我来帮你拆解问题根源,并且给出针对性的修复方案:

问题核心原因

你遇到的报错主要来自三个关键点:

  1. 异步操作时序不匹配:imageCompressor.compress()是异步Promise操作,当Angular首次渲染表格时,results[i]还没被异步回调填充,此时它是undefined,直接访问.size就会触发报错。
  2. var变量的闭包陷阱:循环里用var i会导致所有异步回调共享同一个i变量,最终所有回调都会指向files.length这个越界索引,进一步加剧results[i]的undefined问题。
  3. 全局变量覆盖问题:sizeRound是单个变量,处理多个文件时会被最后一次循环的结果覆盖,所有表格行都会显示同一个压缩比例。

分步修复方案

1. 修正TypeScript代码的异步与闭包问题

先把循环里的var改成let解决变量共享问题,同时新增数组存储每个文件的独立压缩比例,还要提前初始化数组长度避免索引越界:

// 新增数组存储每个文件的压缩比例
results: Blob[] = [];
sizeRounds: string[] = []; 

changeInput() {
  this.img = <HTMLImageElement>document.querySelector('img,#image');
  const inputElement = <HTMLInputElement>document.querySelector('input[type=file],#input');
  this.files = inputElement.files;
  this.inputFlag = true;

  // 提前初始化数组长度,避免索引越界
  this.results = new Array(this.files.length);
  this.sizeRounds = new Array(this.files.length);

  for (let i = 0; i < this.files.length; i++) { // 用let代替var,解决闭包陷阱
    const currentFile = this.files[i];
    const imageCompressor = new ImageCompressor();
    
    imageCompressor.compress(currentFile, { quality: .4 })
      .then((result) => {
        this.results[i] = result;
        // 用当前文件的原始大小计算压缩比例,避免依赖全局变量
        const originalSize = currentFile.size;
        this.sizeRounds[i] = `${Math.round(100 - result.size * 100 / originalSize)}%`;
      });
  }
}

2. 修改HTML模板,安全访问异步数据

在HTML中使用**可选链操作符?.**来安全访问results[i].size,或者用||设置默认占位符,同时绑定对应索引的sizeRounds[i]:

<tr *ngFor="let file of files; let i = index">
  <td style="height: 30px" class="text-center">{{file.name.slice(0,7)}}</td>
  <td style="height: 30px" class="text-center">{{status}}</td>
  <td style="height: 30px" class="text-center"></td>
  <td style="height: 30px" class="text-center">{{file.size}}</td>
  <!-- 可选链+默认值,避免undefined报错 -->
  <td style="height: 30px" class="text-center">{{results[i]?.size || '-'}}</td>
  <td style="height: 30px" class="text-center">{{sizeRounds[i] || '-'}}</td>
</tr>

3. 进阶优化:用Angular规范方式获取DOM元素

尽量避免直接使用document.querySelector,改用Angular的@ViewChild获取DOM元素,更符合组件化思想:

首先在组件类中引入并声明视图引用:

import { ViewChild, ElementRef } from '@angular/core';

@ViewChild('inputFile') inputFile: ElementRef<HTMLInputElement>;
@ViewChild('imageElement') imageElement: ElementRef<HTMLImageElement>;

然后修改HTML标签添加模板引用:

<input #inputFile type="file" accept="image/*" autocomplete="off" style="display: none" draggable="true" (change)='changeInput()' multiple>
<!-- 给img标签也添加模板引用 -->
<img #imageElement id="image" ...>

最后在changeInput中替换DOM获取方式:

this.img = this.imageElement.nativeElement;
this.files = this.inputFile.nativeElement.files;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:21:46