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

Angular/Angular Animations实现监听Flex子Div resize并调整为正方形

解决方案:Angular中监听Flex子元素Resize并调整为正方形

当然可以实现!我给你两种实用的方案,分别用Angular原生API和Angular Animations来搞定这个需求,适配不同的场景:


方案一:使用ResizeObserver + Angular Renderer2(最直接高效)

这个方案利用浏览器原生的ResizeObserver API,能精准监听每个子元素的尺寸变化——不管父元素是点击缩小、窗口 resize 还是其他方式改变尺寸,都能实时响应,比监听window.resize靠谱多了,而且性能经过浏览器优化。

实现代码

模板(HTML)

<div class="parent-flex" (click)="toggleParentSize()">
  <div class="flex-child" *ngFor="let item of items" #flexChild></div>
</div>

样式(CSS)

.parent-flex {
  display: flex;
  width: 800px;
  height: 200px;
  background: #eee;
  transition: width 0.3s ease; /* 给父元素尺寸变化加过渡,让resize更平滑 */
  cursor: pointer;
}

.flex-child {
  flex: 1;
  margin: 0 5px;
  background: #2196F3;
}

组件类(TypeScript)

import { Component, ElementRef, QueryList, ViewChildren, Renderer2, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-flex-square',
  templateUrl: './flex-square.component.html',
  styleUrls: ['./flex-square.component.css']
})
export class FlexSquareComponent implements OnInit, OnDestroy {
  items = [1,2,3,4]; // 模拟多个子元素
  @ViewChildren('flexChild') flexChildren!: QueryList<ElementRef>;
  private resizeObservers: ResizeObserver[] = [];

  constructor(private renderer: Renderer2) {}

  ngOnInit(): void {
    this.initResizeListeners();
  }

  // 初始化尺寸监听
  initResizeListeners() {
    this.flexChildren.forEach(childEl => {
      const observer = new ResizeObserver(entries => {
        entries.forEach(entry => {
          // 获取子元素当前宽度,设置高度等于宽度,变成正方形
          const currentWidth = entry.contentRect.width;
          this.renderer.setStyle(childEl.nativeElement, 'height', `${currentWidth}px`);
        });
      });
      observer.observe(childEl.nativeElement);
      this.resizeObservers.push(observer);
    });
  }

  // 点击父元素切换宽度,模拟缩小/放大效果
  toggleParentSize() {
    const parentEl = document.querySelector('.parent-flex');
    if (!parentEl) return;
    
    const currentWidth = parseInt(getComputedStyle(parentEl).width);
    const newWidth = currentWidth === 800 ? 400 : 800;
    this.renderer.setStyle(parentEl, 'width', `${newWidth}px`);
  }

  // 组件销毁时取消监听,避免内存泄漏
  ngOnDestroy(): void {
    this.resizeObservers.forEach(observer => observer.disconnect());
  }
}

方案二:结合Angular Animations(带过渡动画)

如果希望子元素从矩形变成正方形的过程有平滑的动画过渡,就可以把ResizeObserver和Angular Animations结合起来,让高度变化更丝滑。

实现代码

组件类(TypeScript,新增动画相关代码)

首先导入动画模块和变更检测器:

import { Component, ElementRef, QueryList, ViewChildren, Renderer2, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';

然后添加动画配置,并修改监听逻辑:

@Component({
  selector: 'app-flex-square',
  templateUrl: './flex-square.component.html',
  styleUrls: ['./flex-square.component.css'],
  animations: [
    trigger('squareAnimation', [
      state('*', style({
        height: '{{targetHeight}}px'
      }), { params: { targetHeight: 0 } }),
      transition('* <=> *', animate('0.3s ease'))
    ])
  ]
})
export class FlexSquareComponent implements OnInit, OnDestroy {
  items = [1,2,3,4];
  @ViewChildren('flexChild') flexChildren!: QueryList<ElementRef>;
  private resizeObservers: ResizeObserver[] = [];
  childHeights: number[] = []; // 存储每个子元素的目标高度

  constructor(private renderer: Renderer2, private cdr: ChangeDetectorRef) {}

  ngOnInit(): void {
    this.initResizeListeners();
  }

  initResizeListeners() {
    this.flexChildren.forEach((childEl, index) => {
      const observer = new ResizeObserver(entries => {
        entries.forEach(entry => {
          const currentWidth = entry.contentRect.width;
          this.childHeights[index] = currentWidth;
          // 手动触发变更检测,因为ResizeObserver运行在Angular变更检测之外
          this.cdr.detectChanges();
        });
      });
      observer.observe(childEl.nativeElement);
      this.resizeObservers.push(observer);
    });
  }

  // 点击切换父元素尺寸的方法和之前一致
  toggleParentSize() {
    const parentEl = document.querySelector('.parent-flex');
    if (!parentEl) return;
    
    const currentWidth = parseInt(getComputedStyle(parentEl).width);
    const newWidth = currentWidth === 800 ? 400 : 800;
    this.renderer.setStyle(parentEl, 'width', `${newWidth}px`);
  }

  ngOnDestroy(): void {
    this.resizeObservers.forEach(observer => observer.disconnect());
  }
}

修改模板(HTML)

给子元素绑定动画:

<div class="parent-flex" (click)="toggleParentSize()">
  <div class="flex-child" *ngFor="let item of items; let i = index" #flexChild [@squareAnimation]="{value: '', params: { targetHeight: childHeights[i] }}"></div>
</div>

注意事项

  1. 内存泄漏防范:一定要在组件销毁时调用ResizeObserver.disconnect(),避免残留监听导致内存泄漏。
  2. 变更检测:ResizeObserver的回调函数运行在Angular的变更检测周期之外,所以在方案二中需要手动调用detectChanges()更新视图。
  3. 通用性:ResizeObserver能监听任何元素的尺寸变化,不管父元素的尺寸变化是来自点击、绑定数据还是其他操作,都能正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:24:35