安装依赖
npm i @babel/plugin-proposal-decorators -D
配置.babelrc
{
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]
}
实现一个简单的日志打印方法
// TestDecorator.tsx
function Log(target: any, name: string, descriptor: any): any {
// 这里是缓存原始值,用于在拦截器最后运行原始方法
const oldValue = descriptor.value;
// 实现一个拦截器,在拦截器中实现日志打印,并在最后返回旧值的结果
descriptor.value = function log() {
// 实现日志打印
console.log(
`%c[${logid}]调用了方法:${name},参数为:`,
"color: orange;",
Array.from(arguments)
);
// 调用原始方法实现原始逻辑
return oldValue.apply(this, arguments);
};
// 最后返回一个新的描述器
return descriptor;
};
export default Log;
调用装饰器
// TestComponent.tsx
import * as React from "react";
import Log from "./TestDecorator";
// 属性接口
export interface IProps {
name: string;
age?: number;
}
class TestComponent extends React.Component<IProps, object> {
// 状态
public state: any = {
sum: 0
};
// 调用装饰器
@Log
public add(a: number, b: number): void {
this.setState({
sum: a + b
});
}
public render() {
const { name, age = 0 } = this.props;
const { sum } = this.state;
return (
<div
onClick={() => {
this.add(sum, age);
}}
>
你好,我叫:{name},计数器:{sum},{age ? `今年${age}岁了` : ""}
{this.props.children}
</div>
);
}
}
export default TestComponent;
实现一个可传递参数的装饰器
// TestDecorator.tsx
// 定义一个修饰器
function Logger(logid: string, handler: (name: string) => void) {
// 采用高阶函数的方式进行封装,可接受额外的参数,如外层可接受logid和触发的回调,返回的方法才是真正对类或者方法处理的方法
return function Log(target: any, name: string, descriptor: any): any {
// 这里是缓存旧的方法,也就是上面那个add()原始方法
const oldValue = descriptor.value;
// 这里修改了方法,使其作用变成一个打印函数
// 最后依旧返回旧的方法,真是巧妙
descriptor.value = function log() {
console.log(
`%c[${logid}]调用了方法:${name},参数为:`,
"color: orange;",
Array.from(arguments)
);
// 触发回调原函数
const args = Array.prototype.slice.call(arguments);
args.unshift(name);
handler.apply(this, args);
return oldValue.apply(this, arguments);
};
return descriptor;
};
}
export default Logger;
// TestComponent.tsx
import * as React from "react";
import Log from "./TestDecorator";
export interface IProps {
name: string;
age?: number;
}
class TestComponent extends React.Component<IProps, object> {
public state: any = {
sum: 0
};
@Log("日志打印", (name, ...args) => {
console.log(`触发回调[${name}]:`, args);
})
public add(a: number, b: number): void {
this.setState({
sum: a + b
});
}
public render() {
const { name, age = 0 } = this.props;
const { sum } = this.state;
return (
<div
onClick={() => {
this.add(sum, age);
}}
>
你好,我叫:{name},计数器:{sum},{age ? `今年${age}岁了` : ""}
{this.props.children}
</div>
);
}
}
export default TestComponent;
这样,我们就已经实现了一个简单的日志打印的装饰器了。从上面的实例我们可以看出,其实装饰器本质上就是React中的HOC,即高阶组件,这个高阶函数接收一个方法、类、变量等参数,在内部进行一定的出处理后返回一个新的方法、类、变量,以此来达到我们的要对目标方法、类、变量进行预处理的目的。