Angular:如何复用GridComponent并根据场景加载不同子组件
1. 重构GridComponent模板,改为内容投影容器
把原来硬编码的title1-4和content1-4替换为<ng-content>,通过select属性指定每个卡片的位置,让父组件可以灵活传入任意子组件:
<div class="container col-md-6"> <div class="row"> <div class="card-group"> <div class="card h-100"> <!-- 第一个卡片的内容投影槽 --> <ng-content select="[card-position='1']"></ng-content> </div> <div class="card h-100"> <!-- 第二个卡片的内容投影槽 --> <ng-content select="[card-position='2']"></ng-content> </div> </div> </div> <div class="row"> <div class="card-group"> <div class="card h-100"> <!-- 第三个卡片的内容投影槽 --> <ng-content select="[card-position='3']"></ng-content> </div> <div class="card h-100"> <!-- 第四个卡片的内容投影槽 --> <ng-content select="[card-position='4']"></ng-content> </div> </div> </div> </div>
2. 创建独立的卡片子组件
为每类数据(天气、新闻、推特等)单独创建组件,每个组件负责自己的标题和内容渲染。比如创建WeatherCardComponent:
组件模板(weather-card.component.html):
<div class="card-body"> <h5 class="card-title">天气</h5> <!-- 这里写天气相关的内容逻辑,比如绑定组件内的数据 --> <p class="card-text">今日气温:{{ temperature }}°C</p> </div>
组件类(weather-card.component.ts):
import { Component } from '@angular/core'; @Component({ selector: 'app-weather-card', templateUrl: './weather-card.component.html' }) export class WeatherCardComponent { // 可通过服务或输入属性获取数据 temperature = 25; }
同理,创建NewsCardComponent、TwitterCardComponent、SettingsCard5Component、SettingsCard6Component等,每个组件对应一类数据的展示逻辑。
3. 在父组件中使用GridComponent,传入对应卡片
在首页(HomeComponent)的模板中,将需要的4个卡片组件放到app-grid标签内,通过card-position属性指定位置:
<app-grid> <app-weather-card card-position="1"></app-weather-card> <app-news-card card-position="2"></app-news-card> <app-twitter-card card-position="3"></app-twitter-card> <app-sports-card card-position="4"></app-sports-card> </app-grid>
在设置页(SettingsComponent)的模板中,传入另一组卡片:
<app-grid> <app-settings-card5 card-position="1"></app-settings-card5> <app-settings-card6 card-position="2"></app-settings-card6> <app-twitter-card card-position="3"></app-twitter-card> <app-sports-card card-position="4"></app-sports-card> </app-grid>
为什么构造函数传递组件无效?
Angular的构造函数是用来注入依赖(比如服务、路由等)的,不是用来传递子组件或视图内容的。组件间传递视图内容的标准方式是内容投影,传递数据则用@Input输入属性,这是Angular组件交互的核心机制。
可选优化:用输入属性传递卡片配置(适合卡片结构高度一致的场景)
如果所有卡片结构完全相同,仅标题和数据不同,可以不用创建多个子组件,而是给GridComponent传入卡片配置数组:
GridComponent类:
import { Component, Input } from '@angular/core'; interface CardConfig { title: string; content: string | any; // 支持字符串或复杂数据结构 } @Component({ selector: 'app-grid', templateUrl: './grid.component.html' }) export class GridComponent { @Input() cards: CardConfig[] = []; }
GridComponent模板:
<div class="container col-md-6"> <div class="row"> <div class="card-group"> <div class="card h-100" *ngFor="let card of cards.slice(0,2)"> <div class="card-body"> <h5 class="card-title">{{ card.title }}</h5> {{ card.content }} </div> </div> </div> </div> <div class="row"> <div class="card-group"> <div class="card h-100" *ngFor="let card of cards.slice(2,4)"> <div class="card-body"> <h5 class="card-title">{{ card.title }}</h5> {{ card.content }} </div> </div> </div> </div> </div>
首页父组件中传入配置:
<app-grid [cards]="[ { title: '天气', content: '今日气温25°C' }, { title: '新闻', content: '最新科技资讯' }, { title: '推特', content: '热门推文' }, { title: '体育', content: '赛事播报' } ]"></app-grid>
这种方式更适合卡片结构统一的场景,内容投影则更适合每个卡片有独立交互逻辑的情况。
内容的提问来源于stack exchange,提问作者Vejdis

