Angular 11中如何获取ContentChild的TemplateRef渲染后的宽高
错误原因
你的写法存在两个核心问题:
TemplateRef是Angular模板的抽象引用,仅代表模板的结构定义,本身不对应任何实际渲染的DOM节点,给@ContentChild(TemplateRef)添加read: ElementRef配置会拿到无效引用,自然会触发报错。*ngFor渲染列表是异步操作,ngAfterViewInit生命周期触发时,列表的DOM节点大概率还没有完成渲染,此时查询DOM只能拿到undefined。
解决方案
修改思路是直接查询动态渲染后的卡片容器,等容器渲染完成后再从容器中读取子元素的尺寸,具体实现如下:
1. 修改组件模板
给每个包裹卡片的列容器添加模板引用变量#cardContainer:
<div class="row"> <div class="col-lg-4 col-md-6" *ngFor="let i of items" #cardContainer> <ng-container *ngTemplateOutlet="template; context: {$implicit: i}"></ng-container> </div> </div>
2. 修改组件逻辑
用@ViewChildren查询所有卡片容器,监听容器渲染完成后读取尺寸:
import { Component, Input, ContentChild, TemplateRef, ViewChildren, QueryList, ElementRef, AfterViewInit, AfterViewChecked } from '@angular/core'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.scss'] }) export class ListComponent implements AfterViewInit, AfterViewChecked { @Input() items: any[]; @ContentChild(TemplateRef) template: TemplateRef<any>; // 查询所有卡片容器 @ViewChildren('cardContainer') cardContainers: QueryList<ElementRef<HTMLDivElement>>; // 避免重复计算尺寸的标记 private sizeCalculated = false; ngAfterViewInit(): void { // 监听容器变化,当列表项动态更新时重新计算尺寸 this.cardContainers.changes.subscribe(() => { this.sizeCalculated = false; }); } ngAfterViewChecked(): void { // 仅当容器渲染完成、未计算过尺寸、列表有值时执行逻辑 if (this.cardContainers.length && !this.sizeCalculated && this.items?.length) { this.sizeCalculated = true; this.cardContainers.forEach((container, index) => { // 容器的第一个子元素就是你投影的卡片DOM节点 const cardDom = container.nativeElement.firstElementChild; if (cardDom) { const cardWidth = cardDom.offsetWidth; const cardHeight = cardDom.offsetHeight; console.log(`第${index + 1}张卡片尺寸:宽${cardWidth}px,高${cardHeight}px`); // 此处添加你调整其他UI组件布局的逻辑 } }); } } }
注意事项
- 如果卡片内部存在异步加载的内容(比如图片、异步请求渲染的内容),需要等待内容加载完成后再读取尺寸,否则会拿到未渲染完成的错误值,这种场景可以给卡片内的异步资源添加
load事件监听,或者用MutationObserver监听卡片内容变化。 offsetWidth/offsetHeight返回的是包含边框、内边距的实际渲染尺寸,如果你需要不含边框的尺寸可以改用clientWidth/clientHeight。
内容的提问来源于stack exchange,提问作者RRGT19
相关产品推荐
相关产品推荐

