全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-12-22_都快2025年了,你们的前端代码都上装饰器了没?

您的位置:首页 >> 新闻 >> 行业资讯

都快2025年了,你们的前端代码都上装饰器了没? 点击关注公众号,“技术干货”及时达! 可能很多人都听说过 TypeScript 的装饰器,也可能很多人已经在很多 NestJS 项目中使用装饰器了,也有一些前端开发者可能在某些前端框架中使用过一些简单的装饰器,那么你真的知道装饰器在前端还能玩出哪些花吗? 我们今天不讲基础概念,也不写一些你可能在很多文章里都看到过的没有意义的示例代码,我们直接拿装饰器来实战实现一些需求: 一、类装饰器虽然很多前端对于类和面向对象是排斥的、抵触的,但不影响我们这篇文章继续来基于面向对象通过装饰器玩一些事情。 ?我已经写了很多关于面向对象在前端的使用了,实在是不想在这个问题上继续扯了,可以参考本专栏内的其他文章。 虽然但是,不论如何,你可以不用,但你不能不会,更不能不学。 ?不管在前端还是后端,我们可能都会用到类的实例来做一些事情,比如声明一个用户的类,让用户的类来完成一些事情。 我们可能会为类配置名称,比如给 User 类定义为 用户: //声明一个装饰器,用来保存类的文案 functionLabel(label:string){ return(target:any)={ Reflect.set(target,"label",label) } } @Label("用户") classUser{ } ?我们不限制被标记的类,你可以把any 用泛型约束一下,限制这个装饰器可以标记到哪些类的子类上。 ?我们可以通过 Reflect 来获取到类上的元数据,比如 Label 这个类上的 name 属性,通过 Reflect.getMetadata('name', User) 来获取到: //将打印"用户" console.log(Reflect.get(User,"label")) 通过这种方式,我们可以为类标记很多配置,然后在使用的时候就不会在代码里再出现很多类似 “用户” 的魔法值了。如果有改动的话,也只需要将 @Label("用户") 改成 @Label("XXX") 就好了。 当然,事实上我们不会单独为了一个小功能去声明一个装饰器,那样到时候会给类上标记很多的 @ 看着难受,于是我们可以直接声明一个 ClassConfig 的装饰器,用来保存类的各种配置: interfaceIClassConfig{ //刚才的label label?:string //添加一些其他的配置 //表格的空数据文案 tableEmptyText?:string //表格删除提醒文案 tableDeleteTips?:string } functionClassConfig(config:IClassConfig){ return(target:any)={ Reflect.set(target,"config",config) } } @ClassConfig({ label:"用户", tableEmptyText:"用户们都跑光啦", tableDeleteTips:"你确定要删除这个牛逼的人物吗?" }) 当然,我们可以通过 Reflect.getMetadata('config', User) 来获取到 ClassConfig 这个类上的配置,然后就可以在代码里使用这些配置了. ?比如,我们还封装了一个 Table 组件,我们就只需要将 User 这个类传过去,表格就自动知道没数据的时候应该显示什么文案了: ?Table:model="User":list="list"/ 上面的表格内部,可以获取 model 传入的类,再通过 Reflect 来获取到这些配置进行使用,如果没有配置装饰器或者装饰器没有传入这个参数,那么就使用默认值。 二、属性装饰器很多人都知道,装饰器不仅仅可以配置到类上,属性上的装饰器用处更多。 这个和上面第一点中的一样,也可以为属性做一些配置,比如给用户的账号属性做配置,而且我们还可以根据主要功能来声明不同的装饰器,比如表单的 @Form,表格的 @Table 等等。 classUser{ @Field({ label:"账号", //如果下面的没有配置,那我来兜底。 isEmail:true, }) @Form({ //表单验证的时候必须是邮箱 isEmail:true, //表单验证的时候不能为空 isRequired:true, placeholder:"请输入你牛逼的邮箱账号" }) @Table({ //表示表格列的邮箱点击后会打开邮件App isEmail:true, //表格列的宽度 width:200, //需要脱敏显示 isMask:true }) account!:string } 当然,属性的装饰器声明和类的声明方式不太一致: interfaceIFieldConfig{ label?:string isEmail?:boolean } functionField(config:any){ return(target:any,propertyKey:string)={ Reflect.set(target,propertyKey,config) } } 使用 Reflect 获取的时候也不太一致: constfieldConfig=Reflect.get(User.prototype,"account") //将打印出`@Field`配置的属性对象 console.log(fieldConfig) 想象一下,你封装的表格我也这么使用,我虽然没有传入有哪些表格列,但你是不是能够通过属性是否标记了 @Table 装饰器来判断是否需要显示这个邮箱列呢? Table:model="User":list="list"/ 你也可以再封装一些其他的组件,比如表单,比如搜索等等等等,像这样: Input:model="User":field="account"/ 上面的 Input 组件就会自动读取 User 这个类上的 account 属性的配置,然后根据配置来渲染表单和验证表单,是不是美滋滋? 三、方法装饰器和参数装饰器这两个方式的装饰器我们在这篇文章不细讲,等装饰器这玩意在前端能被大家接受,或者前端娱乐圈骂面向对象不再那么狠的时候再细化一下吧,今天我们只讲讲简单使用: 3.1 方法装饰器说到方法装饰器,我想先提一嘴 AOP 编程范式。 ?AOP(Aspect Oriented Programming) 是一种编程范式,它把应用程序切面化,即把应用程序的各个部分封装成可重用的模块,然后通过组合这些模块来构建应用程序。 ?举个简单的例子,我们最开始写好了很多代码和方法: classUser{ add(name:string){ console.log("user"+name+"added!") } delete(name:string){ console.log("user"+id+"deleted!") } } constuser=newUser(); user.add("Hamm") user.delete("Hamm") 以前调用这些方法都是正常的,突然有一天需求变了,只允许超级管理员才能调用这两个方法,你可能会这么写: classUser{ add(name:string){ checkAdminPermission() console.log("user"+name+"added!") } //其他方法 } functioncheckAdminPermission(){ if(!你的条件){ thrownewError("没有权限") } } constuser=newUser(); user.add("Hamm") 虽然也没毛病,但需要去方法内部添加代码,这属于改动了已有的逻辑。 ?而 AOP 存在的意义,就是通过切面来修改已有的代码,比如在方法执行前,执行一段代码,在方法执行后,执行一段代码,在方法执行出错时,执行一段代码,等等。用更小的粒度来减少对已有代码的入侵。像这样: ?classUser{ @AdminRequired add(name:string){ console.log("user"+name+"added!") } } functionAdminRequired(target:any,propertyKey:string,descriptor:PropertyDescriptor){ constoriginalMethod=descriptor.value descriptor.value=function(...args:any[]){ if(你的条件){ returnoriginalMethod.apply(this,args) } thrownewError("没有权限") } } constuser=newUser() console.log(user.add("Hamm")) 「乍一看,我就知道又会有人说:“你这代码不是更多了么?”」 看起来好像是。 但事实上,从代码架构上来说,这没有对原有的代码做任何改动,只是通过 AOP 的方式,在原有代码的基础上,添加了一些前置方法处理,所以看起来好像多了。但当我再加上一些后置的方法处理的话,代码量并没有添加多少,但结构会更清晰,代码入侵也没有。 「传统写法(入侵)」 classTest{ 张三的方法(){ //李四的前置代码 //张三巴拉巴拉写好的代码 //李四的后置代码 } } ?张三:“李四,你为什么用你的代码包围了我的代码!” ?「装饰器写法(不入侵)」 classTest{ @LiSiWantToDoSomething 张三的方法(){ //张三巴拉巴拉写好的代码 } } functionLiSiWantToDoSomething(target:any,propertyKey:string,descriptor:PropertyDescriptor){ constoriginalMethod=descriptor.value descriptor.value=function(...args:any[]){ console.log("李四的前置代码") constresult=originalMethod.apply(this,args) console.log("张三干完了,结果是"+result) return"我是李四,张三的结果被我偷走了" } } 这时,张三的代码完全在不改动的情况下添加了前置和后置代码。 3.2 参数装饰器参数装饰器的使用场景在前端比较少,在 Nest 中比较多,这篇文章就不过多介绍了,如果后续大伙有兴趣我们再聊。 四、总结装饰器是一种新的语法,可以让你的前端代码更加的架构化,增加代码的可维护性。 如果你有兴趣,还可以阅读本专栏内的这些文章: 用TypeScript和装饰器优雅的为前端数据脱敏 TypeScript使用枚举封装和装饰器优雅的定义字典] TypeScript中如何用装饰器替代JSON配置项封装表单 TypeScript装饰器之我们是这么做表单和校验的 当然,其他文章也很有意思哟~ 今天就这样,欢迎继续关注我们的专栏 《用TypeScript写前端》 也欢迎关注我们的开源项目:AirPower4T,里面有很多装饰器在前端的应用场景,也许可以让你耳目一新。 Bye. 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2024-12-06_阿卜杜拉国王科技大学招博后- 年薪50w+(免税) 下一篇:2021-03-19_「转」期待「特别」的你丨NEW ERA青年电影季主竞赛单元征片开启

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价