安裝依賴
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,即高階組件,這個高階函數接收一個方法、類、變量等參數,在內部進行一定的出處理後返回一個新的方法、類、變量,以此來達到我們的要對目標方法、類、變量進行預處理的目的。