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>
注意事项
- 内存泄漏防范:一定要在组件销毁时调用
ResizeObserver.disconnect(),避免残留监听导致内存泄漏。 - 变更检测:
ResizeObserver的回调函数运行在Angular的变更检测周期之外,所以在方案二中需要手动调用detectChanges()更新视图。 - 通用性:
ResizeObserver能监听任何元素的尺寸变化,不管父元素的尺寸变化是来自点击、绑定数据还是其他操作,都能正常工作。
内容的提问来源于stack exchange,提问作者Shashank Arya
相关产品推荐
相关产品推荐

