詳解Vue中Computed與watch的用法與區(qū)別
computed
computed只接收一個(gè)getter函數(shù)
1、getter必須有返回值
2、computed返回一個(gè)只讀響應(yīng)式ref對(duì)象 (只讀、響應(yīng)式、對(duì)象)
注意:omputed只接收一個(gè)getter函數(shù)時(shí),返回的只讀對(duì)象,也就是不能修改他的返回值!
getter觸發(fā)條件
- 1、computed返回值首次被讀取時(shí)
- 2、getter綁定的響應(yīng)式變量被修改時(shí)
<script setup> import { ref,computed } from 'vue' const num = ref(1) //computed返回一個(gè)只讀響應(yīng)式ref對(duì)象computedNum //computedNum是只讀屬性 let computedNum = computed(() => num.value + 1) </script> ? <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <!-- 修改響應(yīng)式變量num 觸發(fā)與之綁定的computed的getter--> <button @click="num++">num++</button> <!-- computedNum是只讀屬性--> <button @click="computedNum++">computedNum++</button> </template>
computed同時(shí)接收getter函數(shù)對(duì)象和setter函數(shù)對(duì)象
1、setter函數(shù)對(duì)象沒有返回值
2、computed返回一個(gè)可讀可寫響應(yīng)式對(duì)象
3、setter函數(shù)對(duì)象有參數(shù),是getter的返回值,也是computed的值
4、修改computed返回值,觸發(fā)setter函數(shù)對(duì)象執(zhí)行,但不會(huì)真正修改computed返回值(setter內(nèi)改變getter計(jì)算值就會(huì)改變computed返回值)
setter觸發(fā)條件
computed返回值被修改時(shí)
實(shí)例:
<script setup> import { ref, computed } from 'vue' const num = ref(1) //getter(只讀) let computedNum = computed(() => num.value + 1) //getter和setter (可讀可寫) let computedNum2 = computed({ get: () => num.value + 1, set: (val) => { console.log(val); //setter中修改ref響應(yīng)式變量num,將觸發(fā)關(guān)聯(lián)的num的getter計(jì)算 //computedNum和computedNum2的getter同時(shí)觸發(fā) num.value++ } }) </script> ? <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <p>computedNum2:{{ computedNum2 }}</p> <button @click="num++">num++</button> <!-- computedNum是只讀屬性,會(huì)有警告提醒 Write operation failed: computed value is readonly--> <button @click="computedNum++">computedNum++</button> <!-- computedNum2是可讀可寫屬性--> <button @click="computedNum2++">computedNum2++</button> </template>
調(diào)試 Computed
使用范圍:僅開發(fā)模式生效
computed的第二參數(shù):帶有 onTrack
和 onTrigger
選項(xiàng)的對(duì)象
onTrack
:getter關(guān)聯(lián)的響應(yīng)式數(shù)據(jù)時(shí)觸發(fā)。onTrigger
:getter關(guān)聯(lián)的響應(yīng)式數(shù)據(jù)被修改時(shí)觸發(fā)
<script setup> import { ref, computed } from 'vue' const num = ref(1) let computedNum = computed(() => num.value + 1, { onTrack: (e) => { console.log('onTrack'); console.log(e); }, onTrigger: (e) => { console.log('onTrigger'); console.log(e); } }) ? </script> ? <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <!--每次 num++將觸發(fā)onTrigger --> <button @click="num++">num++</button> </template>
watchEffect
語法:
- 參數(shù)1:觸發(fā)監(jiān)聽回調(diào)函數(shù),回調(diào)函數(shù)可傳入一個(gè)onInvalidate函數(shù)作為參數(shù)!
- 可選參數(shù)2:對(duì)象,包含3個(gè)可選屬性flush、onTrack、onTrigger
立即執(zhí)行傳入的一個(gè)函數(shù),同時(shí)響應(yīng)式追蹤其依賴,并在其依賴變更時(shí)重新運(yùn)行該函數(shù)。
1、會(huì)立即執(zhí)行一次(和watch的immediate屬性效果一致)
2、關(guān)聯(lián)的響應(yīng)式數(shù)據(jù)被修改時(shí)觸發(fā)
3、會(huì)自動(dòng)感知代碼依賴,和watch不一樣,watchEffect會(huì)主動(dòng)綁定監(jiān)聽數(shù)據(jù)
局限性:不能監(jiān)聽對(duì)象(但可以監(jiān)聽對(duì)象的屬性),只能監(jiān)聽類似ref基本數(shù)據(jù)類型的響應(yīng)式數(shù)據(jù)
立即執(zhí)行 監(jiān)聽基本數(shù)據(jù)類型
<script setup> import { ref, watchEffect } from 'vue' const num = ref(1) //會(huì)立即執(zhí)行一次 watchEffect(() => { console.log('watchEffect'); num.value++ }) </script> ? <template> <p>num: {{ num }}</p> <button @click="num++">num++</button> </template>
停止watchEffect
隱式:組件卸載時(shí)自動(dòng)停止
顯式:調(diào)用watchEffect
返回值
const stop = watchEffect(() => { /* ... */ }) ? // 顯式停止 stop()
清理watchEffect
語法: watchEffect( onInvalidate=>{ onInvalidate(()=>{ }) })
onInvalidate 是一個(gè)函數(shù)!優(yōu)先觸發(fā)!
onInvalidate 執(zhí)行時(shí)機(jī):
1、watchEffect被重新觸發(fā)時(shí)
2、組件卸載時(shí)
注意:關(guān)聯(lián)的響應(yīng)式數(shù)據(jù)首次被修改時(shí)不會(huì)觸發(fā)onInvalidate函數(shù)!
作用: 清理定時(shí)器、事件監(jiān)聽removeEventListener 。。。
import { ref, watchEffect } from 'vue' const num = ref(1) watchEffect((onInvalidate ) => { console.log('watchEffect-1'); num.value++ onInvalidate (()=>{ console.log('onInvalidate-2'); }) console.log('watchEffect-3'); }) ? //1、watchEffect 被重新觸發(fā)時(shí) // onInvalidate-2 // watchEffect-1 // watchEffect-3 //2、組件卸載時(shí) // onInvalidate-2 //3、關(guān)聯(lián)的響應(yīng)式數(shù)據(jù)首次被修改(組件被掛載時(shí)) // watchEffect-1 // watchEffect-3
watchPostEffect 和 watchSyncEffect
watchPostEffect
和 watchSyncEffect
在Vue3.2新增,是watchEffect類似語法糖的東西,
是watchEffect
可選參數(shù)對(duì)象{ flush?: 'pre' | 'post' | 'sync'}
中post和sync的語法糖,pre是默認(rèn)值
推遲觸發(fā)watchPostEffect
watchPostEffect
是watchEffect可選參數(shù)對(duì)象{flush:'post'}
的語法糖
推遲watchEffect觸發(fā)時(shí)機(jī)!組件更新前觸發(fā)!也就是在生命周期onBeforeUpdate
和 onUpdated
之間觸發(fā)
語法:
//推遲觸發(fā)watchEffect watchEffect( () => { /* ... */ }, { flush: 'post' } ) //Vue3.2語法糖watchPostEffect watchPostEffect(()=>{ /* ... */ })
實(shí)例:
//實(shí)驗(yàn)watchEffect第二參數(shù) flush: 'post'屬性 watchEffect(() => { console.log("實(shí)驗(yàn)watchEffect第二參數(shù) {flush: 'post'}屬性"); console.log(obj.age); },{ flush:'post' }) watchEffect(() => { console.log("watchEffect正常時(shí)機(jī)觸發(fā)"); console.log(obj.age); }) //生命周期onUpdated onUpdated(()=>{ console.log('onUpdated()'); }) //生命周期onBeforeUpdate onBeforeUpdate(()=>{ console.log('onBeforeUpdate()'); })
修改obj.age
時(shí),執(zhí)行結(jié)果:
watchEffect正常時(shí)機(jī)觸發(fā)
onBeforeUpdate()
實(shí)驗(yàn)watchEffect第二參數(shù) {flush: 'post'}屬性
onUpdated()
同步觸發(fā)watchSyncEffect
watchSyncEffect
是watchEffect可選參數(shù)對(duì)象{flush:'sync'}
的語法糖
強(qiáng)制效果始終同步觸發(fā)!效率低!也就是默認(rèn)watchEffect之前觸發(fā)
語法:
watchEffect( () => { /* ... */ }, { flush: 'sync' } ) //Vue3.2語法糖watchSyncEffect watchSyncEffect(()=>{ /* ... */ })
watchEffect不能監(jiān)聽對(duì)象
//假設(shè)修改了對(duì)象的屬性值-修改了obj.age const obj = reactive({ name: '小明', age: 18 }) //watchEffect不能監(jiān)聽對(duì)象變化 watchEffect(() => { console.log('watchEffect監(jiān)聽對(duì)象變化'); console.log(obj); }) //watchEffect可以監(jiān)聽對(duì)象屬性變化 watchEffect(() => { console.log('watchEffect監(jiān)聽對(duì)象屬性變化'); console.log(obj.age); }) //watch監(jiān)聽對(duì)象變化 watch(obj, (obj) => { console.log('watch監(jiān)聽對(duì)象變化'); console.log(obj); })
總結(jié):watchEffect
用來監(jiān)聽能監(jiān)聽基本數(shù)據(jù)類型,不能監(jiān)聽對(duì)象,但能監(jiān)聽對(duì)象的屬性;watch能監(jiān)聽基本數(shù)據(jù)類型和對(duì)象!
watch
語法:
- 參數(shù)1-被監(jiān)聽數(shù)據(jù)(形式:?jiǎn)蝹€(gè)數(shù)據(jù)、數(shù)組、帶返回值的回調(diào)函數(shù))
- 參數(shù)2-觸發(fā)監(jiān)聽的回調(diào)函數(shù),無返回值
- 可選參數(shù)3-對(duì)象
{immediate: true,deep:true}
,對(duì)象含2個(gè)可選參數(shù)和Vue2參數(shù)效果一致
Vue3的watch和Vue2的watch是基本一樣的
1、需要指定監(jiān)聽數(shù)據(jù)
2、惰性,只在被監(jiān)聽數(shù)據(jù)變化時(shí)才觸發(fā)(immediate屬性可以設(shè)置在初始化的時(shí)候觸發(fā))
監(jiān)聽單個(gè)數(shù)據(jù)
參數(shù)1被監(jiān)聽數(shù)據(jù)的形式:
1、單個(gè)基本數(shù)據(jù)類型;
2、回調(diào)函數(shù):返回值為單個(gè)基本數(shù)據(jù)類型;
// 偵聽一個(gè) getter //被監(jiān)聽數(shù)據(jù)傳入一個(gè)帶返回值的回調(diào)函數(shù) const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } ) ? // 直接偵聽一個(gè) ref const count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
監(jiān)聽多個(gè)數(shù)據(jù)(傳入數(shù)組)
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
官方文檔總結(jié)
以下代碼截取官方文檔,從TS代碼可以看出很多關(guān)于watch和watchEffect函數(shù)參數(shù)和返回值的細(xì)節(jié)!
computed
computed
只接收一個(gè)getter函數(shù)
getter
觸發(fā)條件:
1、computed返回值首次被讀取時(shí)
2、getter綁定的響應(yīng)式變量被修改時(shí)
computed
同時(shí)接收getter函數(shù)對(duì)象和setter函數(shù)對(duì)象
setter
觸發(fā)條件:computed返回值被修改時(shí)
// 只讀的 function computed<T>( getter: () => T, debuggerOptions?: DebuggerOptions ): Readonly<Ref<Readonly<T>>> ? // 可寫的 function computed<T>( options: { get: () => T set: (value: T) => void }, debuggerOptions?: DebuggerOptions ): Ref<T> interface DebuggerOptions { onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } interface DebuggerEvent { effect: ReactiveEffect target: any type: OperationTypes key: string | symbol | undefined }
watchEffect
- 參數(shù)1-觸發(fā)監(jiān)聽回調(diào)函數(shù),回調(diào)函數(shù)可傳入一個(gè)onInvalidate函數(shù)作為參數(shù)!
- 可選參數(shù)2-對(duì)象,包含3個(gè)可選屬性flush、onTrack、onTrigger
function watchEffect( effect: (onInvalidate: InvalidateCbRegistrator) => void, options?: WatchEffectOptions ): StopHandle ? interface WatchEffectOptions { flush?: 'pre' | 'post' | 'sync' // 默認(rèn):'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } ? interface DebuggerEvent { effect: ReactiveEffect target: any type: OperationTypes key: string | symbol | undefined } ? type InvalidateCbRegistrator = (invalidate: () => void) => void ? type StopHandle = () => void
watch
- 參數(shù)1-被監(jiān)聽數(shù)據(jù)(形式:?jiǎn)蝹€(gè)數(shù)據(jù)、數(shù)組、帶返回值的回調(diào)函數(shù))
- 參數(shù)2-觸發(fā)監(jiān)聽的回調(diào)函數(shù),無返回值
- 參數(shù)3-傳入
{immediate: true,deep:true}
對(duì)象和Vue2參數(shù)效果一致
// 偵聽單一源 function watch<T>( source: WatcherSource<T>, callback: ( value: T, oldValue: T, onInvalidate: InvalidateCbRegistrator ) => void, options?: WatchOptions ): StopHandle ? // 偵聽多個(gè)源 function watch<T extends WatcherSource<unknown>[]>( sources: T callback: ( values: MapSources<T>, oldValues: MapSources<T>, onInvalidate: InvalidateCbRegistrator ) => void, options? : WatchOptions ): StopHandle ? type WatcherSource<T> = Ref<T> | (() => T) ? type MapSources<T> = { [K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never } ? // 參見 `watchEffect` 共享選項(xiàng)的類型聲明 interface WatchOptions extends WatchEffectOptions { immediate?: boolean // 默認(rèn):false deep?: boolean }
以上就是詳解Vue中Computed與watch的用法與區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于Vue Computed watch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項(xiàng)目使用lodash節(jié)流防抖函數(shù)問題解決方案
在lodash函數(shù)工具庫(kù)中,防抖 _.debounce 和節(jié)流 _.throttle 函數(shù)在一些頻繁觸發(fā)的事件中比較常用,這篇文章主要介紹了vue項(xiàng)目使用lodash節(jié)流防抖函數(shù)問題與解決,需要的朋友可以參考下2023-10-10一篇文章告訴你如何實(shí)現(xiàn)Vue前端分頁(yè)和后端分頁(yè)
這篇文章主要為大家介紹了如何實(shí)現(xiàn)Vue前端分頁(yè)和后端分頁(yè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12Vue使用v-model封裝el-pagination組件的全過程
通過封裝el-pagination組件開發(fā)自定義分頁(yè)組件的類似文章網(wǎng)上已經(jīng)有很多了,但看了一圈,總是不如意,于是決定還是自己動(dòng)手搞一個(gè),對(duì)v-model封裝el-pagination組件相關(guān)知識(shí)感興趣的朋友一起看看吧2021-07-07vue如何解決循環(huán)引用組件報(bào)錯(cuò)的問題
這篇文章主要介紹了vue如何解決循環(huán)引用組件報(bào)錯(cuò)的問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09vue項(xiàng)目element?UI?版本升級(jí)過程遇到的問題及解決方案
這篇文章主要介紹了vue項(xiàng)目element?UI?版本升級(jí)過程遇到的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01vue實(shí)現(xiàn)下拉框篩選表格數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)下拉框篩選表格數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09基于vue-simplemde實(shí)現(xiàn)圖片拖拽、粘貼功能
這篇文章主要介紹了基于vue-simplemde實(shí)現(xiàn)圖片拖拽、粘貼功能,需要的朋友可以參考下2018-04-04vue2.x,vue3.x使用provide/inject注入的區(qū)別說明
這篇文章主要介紹了vue2.x,vue3.x使用provide/inject注入的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04