关键词 装饰器
Decorator
元编程
html
装饰器是一种特殊类型的声明,它可以被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息作为参数传入。vue
拷问灵魂的问题! 由于装饰器能够 对业务代码非侵入。ios
本篇先从项目的宏观角度来总结一下Decorator如何组织。git
我会持续分享一些知识整理,若是文章对您有帮助记得点赞鼓励一下哦😁~,也能够经过邮件方式联系我github
文章列表: juejin.im/user/5bc8b9…vuex
邮箱地址: 595506910@qq.comvue-cli
vue-cli3 默认支持Decorator, 年初重写了一个design库主要依赖官方和社区提供的Decorator来实现的组件。 Decorator能够非侵入的装饰类、方法、属性,解耦业务逻辑和辅助功能逻辑。如下是主要的三方Decorator组件,有了这些组件经常使用的Vue特性就能够所有转成Decorator风格了。express
get computedMsg () {return 'computed ' + this.msg}
mounted () {this.greet()}
让Vuex和Vue之间的绑定更清晰和可拓展npm
这个组件彻底依赖于vue-class-component.而且参考vuex-class组件,它具有如下几个属性:编程
建议项目中只引用vue-property-decorator就能够了,避免@Component从vue-class-component和vue-property-decorator两个中随意引用。
总结一下主要就分红这三类:
以上引用方法等详系内容可查看官方文档。要想完整的发挥Decorator的价值就须要根据须要自定义一些装饰器。下面自定义部分就来实现一个记录日志功能的装饰器。
props: {
name: {
type: string,
defalut: ''
}
}
vs
@Prop name:string
复制代码
传统的写法就是配置式的声明,下面这个优雅多了,类型和做用一目了然。
指望的日志格式
{
"logId":"", // 事件Id
"input":"", // 方法输入的内容
"output":"", // 方法输出的内容
"custom":"" // 自定义的日志内容
}
复制代码
实现
export function Logger(logId?: string, hander?: Function) {
const loggerInfo =Object.seal({logId:logId, input:'',output:'', custom: ''});
const channelName = '__logger';
const msgChannel = postal.channel(channelName);
msgChannel.subscribe(logId, logData => {
// 根据业务逻辑来处理日志
console.log(logData);
});
return function (target: any, key: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> {
const oldValue = descriptor.value
descriptor.value = function () {
const args: Array<any> = [];
for (let index in arguments) {
args.push(arguments[index]);
}
loggerInfo.input = `${key}(${args.join(',')})`;
// 执行原方法
const value = oldValue.apply(this, arguments);
loggerInfo.output = value;
hander && (loggerInfo.custom = hander(loggerInfo.input, loggerInfo.output) || '');
// 被调用时,会自动发出一个事件
msgChannel.publish(logId, loggerInfo);
}
return descriptor
}
}
复制代码
使用
// 直接使用很是简洁
@Logger('event_get_detial1')
getDetial(id?: string, category?: string) {
return "详细内容";
}
// 或者使用自定义,让日志和业务逻辑分离
@Logger('event_get_detial2', (input, output) => {
return '我是自定义内容';
})
getDetial2(id?: string, category?: string) {
return "详细内容";
}
...
<button @click="getDetial2('1000', 'a')">获取详情</button>
复制代码
效果: {logId: "event_get_detial2", input: "getDetial2(1000,a)", output: "详细内容", custom: "我是自定义内容"}
, 每次点击按钮都会触发一次。
TODO: 这里还须要对输入参数和输出参数中的引用数据类型作处理。
同时还须要掌握:装饰器工厂、装饰器组合、装饰器求值、参数装饰器、元数据
考虑下各种Decorator叠加和共存的问题,能够参考官网关于装饰器组合描述
Decorator 的目标是在原有功能基础上,添加功能,切忌覆盖原有功能
类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(好比declare的类)
装饰器只能用于类和类的方法,不能用于函数,由于存在函数提高。类是不会提高的,因此就没有这方面的问题。
注意迁移速度、避免一口吃成胖子的作法
不要另起炉灶对主流库建立Decorator库,主流库维护成本很高仍是得有官方来维护,为保证质量不使用我的编写的Decorator库。本身在建立Decorator库时也要有这个意识,仅作一些有必要自定义的。
Decorator 不是管道模式,decorator之间不存在交互,因此必须注意保持decorator独立性、透明性
Decorator 更适用于非业务功能需求
肯定 decorator 的用途后,切记执行判断参数类型
decorator 针对每一个装饰目标,仅执行一次