關鍵詞 裝飾器
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 針對每一個裝飾目標,僅執行一次