Javascript 中的注解(裝飾器)
談及注解/裝飾器,使用過 Java 或 Python 的同學一定會想到一種語法:@Annotate 或 @Decorator,雖然叫法不同,但本質上都是實現(xiàn)同樣的功能,面向切面編程,使你所寫的代碼變得干凈清爽,將一些復雜的邏輯隱藏在注解(裝飾器)中。
但是,在 Javascript 的標準語法中,并沒有類似的寫法,如果想要實現(xiàn)類似的語法,那該怎么辦呢?
由于 Javascript 也是一直在進步中,語法越來越豐富,不斷有新的語法提案被提出,其中也就包括了 proposal-decorators 這個提案,其主要提供了一系列在 Javascript 中使用裝飾器的語法及定義。
那么要怎樣才能使用這個語法呢?由于其本身只是一個提案,其語法并不能直接使用,不過 Babel 提供了其語法支持:@babel/plugin-proposal-decorators
與 Vue 一起使用
既然能夠在 Javascript 中使用注解,那么能不能在 Vue 項目中使用該語法呢,Vue2 Annotate 便解決了該問題,通過引用該框架,便可以將 Vue 項目重構為使用注解(裝飾器)的項目。
為了簡單演示,所以演示代碼基于 vue-cli v4.5.0 構建的初始化項目
第一步:配置環(huán)境
首先使用 npm 安裝 Vue2 Annotate
npm install @palerock/vue2-annotate -s
或使用 yarn 添加依賴
yarn add @palerock/vue2-annotate
因為要使用注解語法,我們需要在 Babel 環(huán)境中引入相關語法依賴:
npm:
npm install @babel/plugin-proposal-decorators npm install @babel/plugin-proposal-class-properties
yarn:
yarn add @babel/plugin-proposal-decorators yarn add @babel/plugin-proposal-class-properties
@babel/plugin-proposal-decorators 是支持注解語法的插件,@babel/plugin-proposal-class-properties 是支持將 class 語法轉化為 es5 的語法插件,因為 Vue CLI 項目本身就有 Babel 7 的依賴,所以只需要引入這兩個關鍵插件
安裝依賴完成后,配置根目錄下 babel.con 文件內(nèi)容如下:
module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ], "plugins": [ [ "@babel/plugin-proposal-decorators", { "legacy": true } ], [ "@babel/plugin-proposal-class-properties", { "loose": true } ] ] };
第二步:使用注解(裝飾器)
首先,我們需要知道 Vue2 Annotate 為我們提供了哪些注解,通過文檔,我們可以知道其核心注解為 @VueComponent,正常情況下,在一個 Vue 項目中,一般通過以下代碼聲明一個組件:
export default { name: 'HelloWorld' }
如果我們使用 Vue2 Annotate, 那么將變?yōu)椋?/p>export default @VueComponent class HelloWorld {}
可以看出,原來是申明為一個對象,在使用注解后,聲明的內(nèi)容是一個 class
那么如果要定義一些屬性或方法呢,在使用 Vue2 Annotate 的情況下我們可以通過直接聲明成員變量來定義:
export default @VueComponent class HelloWorld { message = 'hello annotate'; alertMessage(){ aler); } }
至此,感受到不一樣了么,在沒有使用注解的情況下,應該是如下所示:
export default { name: 'HelloWorld', data(){ return { message: 'hello annotate' } }, methods: { alertMessage(){ aler); } } }
由于注解是基于 class,你甚至可以在內(nèi)部直接定義 getter 或 setter:
export default @VueComponent class HelloWorld { message = 'hello annotate'; // 獲取 message 內(nèi)容以空格分割的最后一部分 get lastPartOfMessage(){ const parts = (' '); return parts[ - 1]; } // 將 message 中以空格分割的最后一部分改為指定內(nèi)容 set lastPartOfMessage(value){ const parts = (' '); parts[ - 1] = value; = (' '); } // 通過該方法改變 message 的值 displayAndChangeMessage(){ con); // 'annotate' = 'vue2-annotate'; // 改變最后一部分的內(nèi)容 con); // 'vue2-annotate' con(); // 'hello vue2-annotate' } }
是不是相當簡單直觀,其效果和在不使用注解時使用 computed 完全一致,但如果不想使用 getter / setter 方法呢,我們可以通過引入 @Computed 注解實現(xiàn)和 Vue 中配置 computed 完全一致的效果,比如將以上代碼轉化為使用 @Computed
export default @VueComponent class HelloWorld { message = 'hello annotate'; @Computed lastPartOfMessage = { // 獲取 message 內(nèi)容以空格分割的最后一部分 get(){ const parts = (' '); return parts[ - 1]; }, // 將 message 中以空格分割的最后一部分改為指定內(nèi)容 set(value){ const parts = (' '); parts[ - 1] = value; = (' '); } }; // 通過該方法改變 message 的值 displayAndChangeMessage(){ con); // 'annotate' = 'vue2-annotate'; // 改變最后一部分的內(nèi)容 con); // 'vue2-annotate' con(); // 'hello vue2-annotate' } }
其效果和以下配置效果完全一致:
export default { name: 'HelloWorld', data(){ return { message: 'hello annotate' } }, computed: { // 獲取 message 內(nèi)容以空格分割的最后一部分 get(){ const parts = (' '); return parts[ - 1]; }, // 將 message 中以空格分割的最后一部分改為指定內(nèi)容 set(value){ const parts = (' '); parts[ - 1] = value; = (' '); } }, methods: { // 通過該方法改變 message 的值 displayAndChangeMessage(){ con); // 'annotate' = 'vue2-annotate'; // 改變最后一部分的內(nèi)容 con); // 'vue2-annotate' con(); // 'hello vue2-annotate' } } }
那么定義需要暴露出去的參數(shù) —— props 呢,在使用注解的情況下,我們除了 @VueComponent 還需要引入一個注解 @Props
export default @VueComponent class HelloWorld { @Props msg = String; }
十分簡單,其效果和以下代碼一致:
export default { name: 'HelloWorld', props: { msg: String } }
類似的注解還有 @Watch 用于監(jiān)聽屬性改變:
export default @VueComponent class A { // $$ 表示前綴,用于避免與監(jiān)聽屬性沖突 @Watch $$gender(val, oldVal) { } @Watch({deep: true, immediate: true}) $$age(val, oldVal) { } @Watch('name') handleNameChanged = 'handleAgeChanged'; @Watch({property: 'name', deep: true}) handleNameChanged2(val, oldVal) { } }
相當于:
export default { name: 'A', watch: { age: { handler(val, oldVal) { }, deep: true, immediate: true }, gender(val, oldVal) { }, name: [ 'handleAgeChanged', { handler(val, oldVal) { } } ] } }
通過使用注解,可以簡化很多煩雜的操作,比如 @Model 注解,顧名思義,這個注解適用于支持 Vue 中的 v-model 指令,例子如下:
export default @VueComponent class CustomInput { @Model('value') // prop 屬性為 value, 被裝飾屬性名為 content content = String; }
以上代碼申明了一個類型為 String,名為 value 的參數(shù),并將其設為 model,與通常 Vue 項目中以下代碼效果完全一致:
export default { name: 'CustomInput', props: { value: String }, model: { prop: 'value', event: 'change' }, computed: { content: { get() { return ; }, set(value) { this.$emit('change', value); } } } }
除了以上注解,作者表示還有更多的注解正在開發(fā)中,如 @Provide, @Inject 等,但如果現(xiàn)在就想要使用這些功能呢,該插件提供了一個將 Vue 原配置轉化為可以在 class 中使用的注解:@NativeApi,示例如下:
@VueComponent class HelloWorld{ @NativeApi components = {}; @NativeApi provide(){ return { message: 'message' }; } @NativeApi inject = ['parentProvide']; @NativeApi data(){ return { message: 'hello annotate' } } @NativeApi computed = { test(){ return ''; } }; @NativeApi created(){ // 生命周期函數(shù) } // ...等等 }
等同于:
export default{ name: 'HelloWorld', components : {}, provide(){ return { message: 'message' }; }, inject: ['parentProvide'], data(){ return { message: 'hello annotate' } }, computed: { test(){ return ''; } }, created(){ // 生命周期函數(shù) } }
總結
注解(裝飾器)語法可以使項目變得簡單明了,在 Java 的開發(fā)中,相信有不少小伙伴對注解的魅力有著不淺的認識吧,而在 Javascript 的 Vue 項目中,使用注解(裝飾器)語法也是相當簡潔優(yōu)雅的,其缺點也是明顯,由于語法處于提案狀態(tài),使用它需要 Babel 進行額外的編譯工作,配置額外的環(huán)境,不過現(xiàn)在就算是 TypeScript 也需要編譯才能運行,無傷大雅。
1.《.vue 如何寫注釋?我來告訴你答案在 Vue 中使用注解(裝飾器)》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡信息知識,僅代表作者本人觀點,與本網(wǎng)站無關,侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《.vue 如何寫注釋?我來告訴你答案在 Vue 中使用注解(裝飾器)》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉載時請保留本站內(nèi)容來源地址,http://f99ss.com/gl/2228835.html