Angular中如何展示动态ViewModel并通过字符串名获取模型属性值
Angular动态报表组件实现方案(支持任意ViewModel)
核心问题的解决本质是利用JS/TS原生的动态属性访问语法,不需要引入第三方库就能实现。
核心:字符串属性名动态取值实现
- 单层属性直接用方括号语法访问,这是JS原生支持的特性:
// 任意结构的ViewModel实例 const userVM = { name: "李四", age: 30, post: "前端工程师" }; // 字符串类型的属性名 const key = "name"; // 动态取值结果为"李四" const value = userVM[key];
- 如果是嵌套结构的属性(比如
department.leader.name这种多层路径),写一个轻量的路径解析工具函数即可,不需要引入额外依赖:
/** * 根据点分隔的属性路径获取对象嵌套值 * @param target 目标ViewModel实例 * @param propPath 属性路径字符串,比如 'user.contact.email' * @returns 对应属性值,路径不存在时返回undefined */ function getValueByPath(target: Record<string, any>, propPath: string): any { return propPath.split('.').reduce((current, key) => { return current ? current[key] : undefined; }, target); }
通用动态报表组件完整实现
1. 组件核心逻辑
组件只需要约定两个输入参数,不需要和具体ViewModel耦合:
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-dynamic-report', styles: [` .report-table { width: 100%; border-collapse: collapse; } .report-table th, .report-table td { border: 1px solid #eee; padding: 8px; } `], template: ` <table class="report-table"> <thead> <tr> <th *ngFor="let col of columnConfigs" [style.text-align]="col.align || 'left'"> {{ col.label }} </th> </tr> </thead> <tbody> <tr *ngFor="let row of dataList"> <td *ngFor="let col of columnConfigs" [style.text-align]="col.align || 'left'"> <!-- 动态取值渲染,支持传入自定义格式化函数 --> {{ col.formatter ? col.formatter(getValueByPath(row, col.prop)) : getValueByPath(row, col.prop) }} </td> </tr> </tbody> </table> ` }) export class DynamicReportComponent { /** * 报表数据源,支持任意结构的ViewModel数组 */ @Input() dataList: Record<string, any>[] = []; /** * 列配置数组 * 配置项说明: * - label: 列表头显示文本 * - prop: 对应绑定的属性名/属性路径(字符串类型) * - align: 可选,列对齐方式 * - formatter: 可选,值格式化函数 */ @Input() columnConfigs: Array<{ label: string; prop: string; align?: 'left' | 'center' | 'right'; formatter?: (value: any) => string | number; }> = []; getValueByPath(target: Record<string, any>, propPath: string): any { return propPath.split('.').reduce((current, key) => { return current ? current[key] : undefined; }, target); } }
2. 业务侧使用方式
不管是用户ViewModel、订单ViewModel还是其他任意业务模型,只需要传入对应的数据和列配置即可,不需要修改动态报表组件的代码:
// 业务组件中示例:用订单ViewModel渲染报表 interface OrderVM { orderNo: string; amount: number; buyer: { name: string; phone: string; }; payTime: string; } // 列配置,prop字段直接写对应属性的字符串名/路径 orderColumns = [ {label: '订单号', prop: 'orderNo', align: 'left'}, {label: '订单金额', prop: 'amount', align: 'right', formatter: (val) => `¥${val.toFixed(2)}`}, {label: '买家姓名', prop: 'buyer.name', align: 'left'}, {label: '买家电话', prop: 'buyer.phone', align: 'left'}, {label: '支付时间', prop: 'payTime', align: 'left'} ]; // 接口返回的实际业务数据 orderList: OrderVM[] = [];
业务组件模板中直接调用:
<app-dynamic-report [dataList]="orderList" [columnConfigs]="orderColumns" ></app-dynamic-report>
3. 扩展建议
- 如果需要支持自定义单元格渲染(比如按钮、标签、进度条等特殊组件),可以结合
ngTemplateOutlet实现动态模板注入,在列配置中支持传入自定义模板引用即可。 - 不要为了方便直接给组件输入设置any类型,用
Record<string, any>做通用类型约束,能避免很多低级的拼写错误。 - 如果属性路径存在数组场景(比如
orderItems[0].productName),只需要扩展getValueByPath函数,增加数组下标解析逻辑就行,核心思路不变。
内容的提问来源于stack exchange,提问作者behinafzar bahrami
相关产品推荐
相关产品推荐

