實現(xiàn)一個VUE響應式屬性裝飾器詳析
前言
使用面向對象的開發(fā)思想難免會用到類,既然有了類,那就應該有實例,然而我們使用類的時候可能需要實例中的某個屬性是vue的響應屬性,也可能里面的某個方法也可以被vue的watch監(jiān)聽。我就開始琢磨如何通過 Composition API
來實現(xiàn)這個類屬性裝飾器
不使用任何的響應Api
// TestReactive.ts export class TestReactive { count = 0; loopSetCount() { setInterval(() => { this.count++; }, 1000); } }
// App.vue <template> <div>{{data.count}} </div> </template> <script setup lang="ts"> import { TestReactive } from './TestReactive' const data = new TestReactive() data.loopSetCount() </script> </script>
通過以上代碼可以看到我調用 loopSetCount
這個方法的作用就是想讓data實例對象中的count每間隔1s就加1 同時也想讓template模板中的 {{data.count}}
響應,但這樣操作他是不會響應的因為我們的 count
并非是 Composition API
提供的響應式數(shù)據(jù)。
使用 reactive 實現(xiàn)
最初的做法很簡單把實例裹了一層 reactive
,果不其然view層動態(tài)渲染了,但是這樣就會導致我整個實例中所有的方法以及屬性都會是響應式數(shù)據(jù),最終不是想要的效果
const data = reactive(new TestReactive())
使用 ref 實現(xiàn)
后面我又想了一個好方法就是把想要響應式的屬性賦一個 ref
對象,這樣也能實現(xiàn)同樣的效果,但是在賦值的時候還得必須用到 .value
,感覺很不優(yōu)雅。
// 去除reactive的包裹 const data = new TestReactive()
// TestReactive.ts import { ref } from "vue"; export class TestReactive { count = ref<number>(0); loopSetCount() { setInterval(() => { this.count.value++; }, 1000); } }
使用裝飾器實現(xiàn)
實現(xiàn)Reactive裝飾器
最終又想了一個方案就是我想要哪個類屬性實現(xiàn)vue的響應,那我只需要用裝飾器裝飾一下這個屬性,即可讓view層跟著數(shù)據(jù)變化。
我們裝飾的是類屬性首先你得要了解類型裝飾器的規(guī)則,具體請參考TypeScript手冊
屬性裝飾器聲明在一個屬性聲明之前(緊靠著屬性聲明)。 屬性裝飾器不能用在聲明文件中(.d.ts),或者任何外部上下文(比如 declare
的類)里。
屬性裝飾器表達式會在運行時當作函數(shù)被調用,傳入下列2個參數(shù):
- 對于靜態(tài)成員來說是類的構造函數(shù),對于實例成員是類的原型對象。
- 成員的名字。
注意 屬性描述符不會做為參數(shù)傳入屬性裝飾器,這與TypeScript是如何初始化屬性裝飾器的有關。 因為目前沒有辦法在定義一個原型對象的成員時描述一個實例屬性,并且沒辦法監(jiān)視或修改一個屬性的初始化方法。返回值也會被忽略。因此,屬性描述符只能用來監(jiān)視類中是否聲明了某個名字的屬性。
// TestReactive.ts import { ref } from "vue"; function Reactive(target: any, key: string) { const value = ref(); Reflect.defineProperty(target, key, { get() { return value.value; }, set(v) { value.value = v; }, }); } export class TestReactive { @Reactive count = 0; loopSetCount() { setInterval(() => { this.count++; }, 1000); } }
通過以上代碼使用Reactive裝飾一下這個屬性頁面就會跟著變化,而且在賦值的時候也不需要通過this.count.value 去賦值。這樣一來就解決了我們不優(yōu)雅的問題。
實現(xiàn)Watch裝飾器
緊接著我們可以再實現(xiàn)一個Watch的裝飾器專門用于裝飾方法,通過傳遞Reactive裝飾的屬性名稱來監(jiān)聽,一旦Reactive裝飾的屬性變動就會調用Watch裝飾的方法。
import { ref, watch, WatchOptions } from "vue"; function Reactive(target: any, key: string) { const value = ref(); Reflect.defineProperty(target, key, { get() { return value.value; }, set(v) { value.value = v; }, }); } function Watch(watchField: string | string[], watchConfig: WatchOptions = {}) { return function (target: any, key: string, descriptor: PropertyDescriptor) { let watchFn: Array<() => any> | (() => any) = []; if (typeof watchField === "string") { watchFn = () => target[watchField]; } else if (Array.isArray(watchField)) { watchFn = watchField.map((field) => () => target[field]); } watch(watchFn, descriptor.value, watchConfig); }; } export class TestReactive { @Reactive count = 0; @Watch("count") doFetch(newValue: number) { console.log(newValue, "最新的數(shù)據(jù)"); } loopSetCount() { setInterval(() => { this.count++; }, 1000); } }
以上是我實現(xiàn)的一個思路,當我實現(xiàn)完這個功能后,同事告訴我 有一個 mobx 的庫可以像我這樣來操作數(shù)據(jù)響應式,然后我查了一下 mobx for vue
還真找到了一個 mobx-vue 的庫,感覺可以深度的去學習一下。
總結
響應式屬性還是通過Composition API
來實現(xiàn)的,使用裝飾器(Decorators)來進行屬性的操作,讓使用者無感知,只需要知道哪個屬性需要響應我就給誰裝飾。
到此這篇關于實現(xiàn)一個VUE響應式屬性裝飾器詳析的文章就介紹到這了,更多相關 VUE響應式屬性裝飾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue中使用webuploader做斷點續(xù)傳實現(xiàn)文件上傳功能
之前做的一個項目中,由于經(jīng)常上傳幾百兆的壓縮包,導致經(jīng)常上傳失敗,所以就找了webuploader插件做了斷點續(xù)傳,斷點續(xù)傳除了需要前端分片,也需要后臺去支持,所以做的時候做好對接協(xié)調,所以本文就給大家詳細的介紹一下vue中如何使用webuploader做斷點續(xù)傳2023-07-07Vue3之getCurrentInstance與ts結合使用的方式
這篇文章主要介紹了Vue3之getCurrentInstance與ts結合使用的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04vue中使用element ui的input框實現(xiàn)模糊搜索的輸入框
這篇文章主要介紹了vue中使用element ui的input框實現(xiàn)模糊搜索的輸入框,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11Vue中使用vue2-perfect-scrollbar制作滾動條
這篇文章主要介紹了Vue中使用vue2-perfect-scrollbar滾動條,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06