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

Angular父组件基于API返回对象的position属性按序渲染子组件的实现方法

实现基于position属性的子组件动态排序方案

核心思路

你现在的渲染顺序写死在模板结构里,要实现动态排序完全不需要大改现有逻辑,只要做到两点:

  • 给每个分类好的题型组,记录它对应的排序权重(也就是组内题目携带的最小position值)
  • 把所有题型组按这个权重排序后,通过循环渲染代替硬编码的固定组件顺序,避免写死DOM层级

具体代码改动

1. 组件TS逻辑调整

保留你原有的题型分类逻辑,只需要在分类完成后新增排序逻辑,把零散的四个题型数组转换成带排序信息的组列表:

// 新增类型定义,方便类型校验(可选,但是能减少类型报错)
interface ActivityRenderGroup {
  // 标记组对应的子组件类型
  componentType: 'text' | 'mcq' | 'dragDrop' | 'fillBlank';
  // 对应组的题目数组
  activityList: any[];
  // 用于排序的权重值
  order: number;
}

// 新增用来存最终要渲染的组列表的变量
renderableGroups: ActivityRenderGroup[] = [];

textBasedActivity = []; 
mcqActivity = []; 
fillInTheBlanks = []; 
dragndropActivity = [];

extractTypes() {
  // 每次分类前先清空原有的数组,避免重复推送数据
  this.textBasedActivity = [];
  this.mcqActivity = [];
  this.fillInTheBlanks = [];
  this.dragndropActivity = [];

  // 原有分类逻辑完全保留,不做改动
  this.resultActivity.widgets.forEach((element) => {
    if (element.questionType == 'mcqType') {
      this.mcqActivity.push(element);
    } else if (
      element.questionType == 'textType' ||
      element.questionType == 'imageType'
    ) {
      this.textBasedActivity.push(element);
    } else if (element.questionType == 'fillBlankType') {
      this.fillInTheBlanks.push(element);
    } else if (element.questionType == 'dragNDropType') {
      this.dragndropActivity.push(element);
    }
  });

  // 新增:把四个题型数组组装成带排序值的组,再按order从小到大排序
  this.renderableGroups = [
    {
      componentType: 'text',
      activityList: this.textBasedActivity,
      // 取组内最小的position作为排序值;空数组直接给无限大,排到最后
      order: this.textBasedActivity.length ? Math.min(...this.textBasedActivity.map(item => item.position)) : Infinity
    },
    {
      componentType: 'mcq',
      activityList: this.mcqActivity,
      order: this.mcqActivity.length ? Math.min(...this.mcqActivity.map(item => item.position)) : Infinity
    },
    {
      componentType: 'dragDrop',
      activityList: this.dragndropActivity,
      order: this.dragndropActivity.length ? Math.min(...this.dragndropActivity.map(item => item.position)) : Infinity
    },
    {
      componentType: 'fillBlank',
      activityList: this.fillInTheBlanks,
      order: this.fillInTheBlanks.length ? Math.min(...this.fillInTheBlanks.map(item => item.position)) : Infinity
    }
    // 升序排序,order越小越靠前
  ].sort((prev, next) => prev.order - next.order);
}

为什么取组内最小position?因为你的子组件是接收同类型的全部题目做整体渲染的,不会拆分同类型题目,所以只要取这个组里最靠前的题目的position值作为组的排序依据,就能完全匹配题目本身的顺序。空数组被设置为Infinity,排序时会自动排到末尾,后续渲染时直接跳过即可,和你原有的非空判断逻辑效果一致。


2. 模板渲染逻辑调整

把原来硬编码顺序的四个子组件,换成遍历排好序的组列表渲染,用ng-container做嵌套避免生成额外DOM标签破坏原有布局:

<div class="each-activity-base">
  <!-- 遍历已经排好序的组列表 -->
  <ng-container *ngFor="let group of renderableGroups">
    <!-- 只渲染非空的组,和原有逻辑一致 -->
    <ng-container *ngIf="group.activityList.length > 0">
      <!-- 根据组的类型匹配对应的子组件,入参和原有写法完全一致 -->
      <app-text-based-widget 
        *ngIf="group.componentType === 'text'"
        [courseId]="courseId" 
        [activityId]="activityId"
        [moduleId]="moduleId" 
        [studentData]="studentData" 
        [activityObjects]="group.activityList">
      </app-text-based-widget>

      <app-multiple-choice-based-widget 
        *ngIf="group.componentType === 'mcq'"
        [activityObjects]="group.activityList">
      </app-multiple-choice-based-widget>

      <app-drag-drop-based-widget 
        *ngIf="group.componentType === 'dragDrop'"
        [activityObjects]="group.activityList">
      </app-drag-drop-based-widget>

      <app-fill-blanks-based-widget 
        *ngIf="group.componentType === 'fillBlank'"
        [activityObjects]="group.activityList">
      </app-fill-blanks-based-widget>
    </ng-container>
  </ng-container>
</div>

效果说明

  • 渲染顺序完全由题目自带的position值决定:比如拖拽题的起始position是1,选择题的起始position是2,文本题的起始position是3,就会按拖拽题→选择题→文本题的顺序渲染,不会受模板里代码书写顺序影响。
  • 原有子组件的传参、内部逻辑完全没有改动,不需要调整子组件的接口定义。
  • 空的题型组自动跳过渲染,和原有的*ngIf长度判断逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 08:54:04