您好,登錄后才能下訂單哦!
小編給大家分享一下小程序怎么通過watch和computed檢測數據,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
在vue中,computed是一個計算屬性,類似于過濾器,對綁定到view的數據進行處理,并監聽變化。而watch監聽復雜數據類型需用深度監聽。這兩者都可以在vue上實現檢測數據的變化。而微信小程序不同于vue可以使用watch和computed做出相應的改變。小程序中只有函數this.setData()可以檢測數據,所以小程序每次數據改變需要檢測時都必須手動執行函數才可實現。除此之外,小程序還可以附上這兩個功能檢測數據變化。
vue 里是通過 Object.defineProperty 來實現數據變化檢測的,給該變量的 setter 里注入所有的綁定操作,就可以在該變量變化時帶動其它數據的變化。實際上,在小程序里實現要比 vue 里簡單,應為對于 data 里對象來說,vue 要遞歸的綁定對象里的每一個變量,使之響應式化。但是在微信小程序里,不管是對于對象還是基本類型,只能通過 this.setData() 來改變,這樣我們只需檢測 data 里面的 key 值的變化,而不用檢測 key 值里面的 key 。
測試代碼:
Page({ data: { test: { a: 123 }, test1: \'test1\', }, onLoad() { computed(this, { test2: function() { returnthis.data.test.a + \'2222222\' }, test3: function() { returnthis.data.test.a + \'3333333\' } }) watch(this, { test:function(newVal) { console.log(\'invoke watch\') this.setData({test1: newVal.a + \'11111111\' }) } }) }, changeTest() { this.setData({ test:{ a: Math.random().toFixed(5) } }) }, })
現在我們要實現 watch 和 computed 方法,使得 test 變化時,test1、test2、test3 也變化,為此,增加了一個按鈕,當點擊這個按鈕時,test 會改變。
watch 方法相對簡單點,首先我們定義一個函數來檢測變化:
function defineReactive(data, key, val, fn) { Object.defineProperty(data, key, { configurable: true, enumerable: true, get: function() { return val }, set: function(newVal){ if (newVal === val)return fn &&fn(newVal) val = newVal }, }) }
然后遍歷 watch 函數傳入的對象,給每個鍵調用該方法
function watch(ctx, obj) { Object.keys(obj).forEach(key => { defineReactive(ctx.data, key, ctx.data[key], function(value) { obj[key].call(ctx,value) }) }) }
這里有參數是 fn ,即上面 watch 方法里 test 的值,這里把該方法包一層,綁定 context。
接著來看 computed,這個稍微復雜,因為我們無法得知 computed 里依賴的是 data 里面的哪個變量,因此只能遍歷 data 里的每一個變量。
function computed(ctx, obj) { let keys =Object.keys(obj) let dataKeys =Object.keys(ctx.data) dataKeys.forEach(dataKey => { defineReactive(ctx.data, dataKey, ctx.data[dataKey]) }) let firstComputedObj =keys.reduce((prev, next) => { ctx.data.$target =function() { ctx.setData({[next]: obj[next].call(ctx) }) } prev[next] =obj[next].call(ctx) ctx.data.$target =null return prev }, {}) ctx.setData(firstComputedObj) }
詳細解釋下這段代碼,首先給 data 里的每個屬性調用 defineReactive 方法。接著計算 computed 里面每個屬性第一次的值,也就是上例中的 test2、test3。
computed(this, { test2: function() { returnthis.data.test.a + \'2222222\' }, test3: function() { returnthis.data.test.a + \'3333333\' } })
這里分別調用 test2 和 test3 的值,將返回值與對應的 key 值組合成一個對象,然后再調用 setData() ,這樣就會第一次計算這兩個值,這里使用了 reduce 方法。test2 和 test3 都是依賴 test 的,這樣必須在 test 改變的時候在其的 setter 函數中調用 test2 和 test3 中對應的函數,并通過 setData 來設置這兩個變量。
小程序商店提供更多上線小程序
聲明了一個變量來保存所有在變化時需要執行的函數,在 set 時執行每一個函數,因為此時 this.data.test 的值還未改變,使用 setTimeout 在下一輪再執行。現在就有一個問題,怎么將函數添加到 subs 中。不知道各位還是否記得上面我們說到的在 reduce 里的那兩行代碼。因為在執行計算 test1 和 test2 第一次 computed 值的時候,會調用 test 的 getter 方法,此刻就是一個好機會將函數注入到 subs 中,在 data 上聲明一個 $target 變量,并將需要執行的函數賦值給該變量,這樣在 getter 中就可以判斷 data 上有無 target 值,從而就可以 push 進 subs,要注意的是需要馬上將 target 設為 null,
到此為止已經實現了 watch 和 computed,但是還沒完,有個問題。當同時使用這兩者的時候,watch 里的對象的鍵也同時存在于 data 中,這樣就會重復在該變量上調用 Object.defineProperty ,后面會覆蓋前面。因為這里不像 vue 里可以決定兩者的調用順序,因此我們推薦先寫 computed 再寫 watch,這樣可以 watch computed 里的值。
以上是“小程序怎么通過watch和computed檢測數據”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。