首頁 > 微信小程式 > 小程式開發 > 小程式如何透過watch和computed檢測數據

小程式如何透過watch和computed檢測數據

青灯夜游
發布: 2020-04-27 09:30:31
轉載
2838 人瀏覽過

小程式如何透過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,

#到此已經實現了 target 設為 null,

#到此為止已經實現了 target 和 computed,但還沒完,有個問題。當同時使用這兩者的時候,watch 裡的物件的鍵也同時存在於 data 中,這樣就會重複在該變數上呼叫 Object.defineProperty ,後面會覆蓋前面。因為這裡不像 vue 裡可以決定兩者的呼叫順序,因此我們推薦先寫 computed 再寫 watch,這樣可以 watch computed 裡的數值。 推薦:《

小程式開發教學###》###

以上是小程式如何透過watch和computed檢測數據的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板