Angular 7强类型模型属性设置显示别名的实现方案咨询
Angular 7实现类似C# DisplayName的属性别名方案
Angular 7本身并没有像C#的[DisplayName]或者Java注解那样的内置属性别名机制,但我们可以通过自定义装饰器+元数据+自定义管道的方式,实现完全相同的效果——只需要在模型类里修改一次别名,就能全局生效。
1. 实现自定义@DisplayName装饰器
我们利用TypeScript的装饰器和Reflect元数据API,给每个属性存储对应的别名:
// display-name.decorator.ts export function DisplayName(displayName: string) { return function (target: any, propertyKey: string) { // 将别名存入属性的元数据中 Reflect.defineMetadata('displayName', displayName, target, propertyKey); }; }
2. 把接口改为类(关键步骤)
TypeScript的接口是编译时类型,编译后会完全消失,装饰器无法作用在接口属性上。所以我们需要把原来的interface改成class,让装饰器能正常生效:
// some-basic.model.ts import { DisplayName } from './display-name.decorator'; export class SomeBasicModel { @DisplayName('First Name') firstName: string; @DisplayName('Last Name') lastName: string; @DisplayName('Primary Address') address: string; // 可选:构造函数方便把服务端返回的对象转为类实例 constructor(data?: Partial<SomeBasicModel>) { Object.assign(this, data); } }
当你从服务端获取数据时,记得转换为类实例:
// 组件中示例代码 this.myModel = new SomeBasicModel(serverResponseData);
3. 自定义管道替代keyvalue
为了在模板里便捷获取别名,我们写一个自定义管道,自动把模型属性转换成「别名+值」的结构:
// display-key.pipe.ts import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'displayKey' }) export class DisplayKeyPipe implements PipeTransform { transform(model: any): Array<{ displayName: string; value: any }> { if (!model) return []; return Object.keys(model).map(propertyKey => { // 从元数据取别名,无别名则用原属性名兜底 const displayName = Reflect.getMetadata('displayName', model.constructor.prototype, propertyKey) || propertyKey; return { displayName, value: model[propertyKey] }; }); } }
然后在模块中注册这个管道:
// app.module.ts import { DisplayKeyPipe } from './display-key.pipe'; @NgModule({ declarations: [ // ...你的组件、指令 DisplayKeyPipe ] }) export class AppModule { }
4. 在模板中使用
现在就可以像你期望的那样,轻松展示别名了:
<div *ngFor="let item of myModel | displayKey"> {{item.displayName}}: {{item.value}} </div>
备选方案:不用管道,组件内预处理
如果你不想用管道,也可以写工具函数在组件里提前处理数据:
// model-utils.ts export function getModelDisplayItems(model: any) { return Object.keys(model).map(key => ({ displayName: Reflect.getMetadata('displayName', model.constructor.prototype, key) || key, value: model[key] })); }
组件内调用:
// 组件类中 myDisplayItems = getModelDisplayItems(this.myModel);
模板直接遍历myDisplayItems即可。
注意事项
- 确保
tsconfig.json中开启了装饰器支持:"experimentalDecorators": true(Angular CLI项目默认已开启)。 - 若遇
Reflect报错,可安装reflect-metadata库,并在polyfills.ts中添加import 'reflect-metadata';。
这样一来,你只需要在SomeBasicModel类里修改@DisplayName的参数,所有用到该模型的地方都会自动更新显示的别名,完全满足「一处修改,全局生效」的需求。
内容的提问来源于stack exchange,提问作者yanky_cranky
相关产品推荐
相关产品推荐

