- 該文章是在學(xué)習(xí) 小滿vue3 課程的隨堂記錄
- 示例均采用
<script setup>
,且包含typescript
的基礎(chǔ)用法
前言
在 vue3 中,必須是 ref
、reactive
包裹起來的數(shù)據(jù),才可以被 watch
監(jiān)聽到
一、基本使用
1、語法:watch(source, cb, options)
- source 是監(jiān)聽的目標(biāo),有 4 種書寫形式:
-
reactive
形式的響應(yīng)式數(shù)據(jù) -
ref
形式的響應(yīng)式數(shù)據(jù) - 數(shù)組形式:監(jiān)聽多個響應(yīng)式數(shù)據(jù)時(應(yīng)該用的不多)
- 挨個放進(jìn)
數(shù)組
里,如[響應(yīng)式數(shù)據(jù)1, 響應(yīng)式數(shù)據(jù)2]
-
cb
對應(yīng)的函數(shù)參數(shù)
(新值、舊值)也都是數(shù)組
形式,詳見例子
- 挨個放進(jìn)
- 函數(shù)形式:若只想監(jiān)聽
reactive 深層中
的指定屬性
,該指定屬性是-
引用類型
,不需要函數(shù)形式,直接 obj.a.b -
非引用類型
,比如是一個字符串,則需要使用函數(shù)形式
返回,詳見例子
-
-
- cb 是回調(diào)函數(shù),
(newVal,oldVal) => {}
- options 是配置項
-
deep
: 是否開啟深層監(jiān)聽-
reactive
類型的數(shù)據(jù)不需要開啟
,源碼中已做了深層響應(yīng)式 -
ref
類型的數(shù)據(jù)如果需要監(jiān)聽到深層,要設(shè)置為true
(雖然監(jiān)聽到深層,但是 source 不能指定到深層)
-
-
immediate
: 是否立刻執(zhí)行 -
flush
: watch 的執(zhí)行順序。-
pre
組件更新之前執(zhí)行(默認(rèn)) -
sync
同步執(zhí)行; -
post
組件更新之后執(zhí)行
-
-
2、例子
下面代碼中,演示了多個情景下的使用文章來源:http://www.zghlxwxcb.cn/news/detail-653048.html
<input type="text" v-model="xiaoman1" />
<br />
<input type="text" v-model="xiaoman2" />
<br />
<input type="text" v-model="message.foo.bar" />
<br />
<input type="text" v-model="message2.foo.bar" />
const xiaoman1 = ref<string>("小滿1");
const xiaoman2 = ref<string>("小滿2");
const message = ref({
foo: {
bar: "aaaaa",
},
});
const message2 = reactive({
foo: {
bar: "aaaaa",
},
});
watch(xiaoman1, (newVal, oldVal) => {
console.log("監(jiān)聽單個數(shù)據(jù)源", newVal, oldVal);
});
// 用數(shù)組監(jiān)聽多個數(shù)據(jù)源,[新值數(shù)組], [舊值數(shù)組]
watch([xiaoman1, xiaoman2], (newVal, oldVal) => {
console.log("用數(shù)組監(jiān)聽多個數(shù)據(jù)源,[新值數(shù)組], [舊值數(shù)組]", newVal, oldVal);
});
// ref 深層監(jiān)聽
watch(
message,
(newVal, oldVal) => {
// 如果是引用類型,新值 和 舊值 是一樣的
console.log("ref 深層監(jiān)聽&立刻執(zhí)行", newVal, oldVal);
},
{
deep: true, // 深度監(jiān)聽,ref 若需要深度監(jiān)聽,這里要開啟
immediate: true, // callback 立刻先執(zhí)行一次
flush: "pre", // 【watch的執(zhí)行順序】 pre 組件更新之前調(diào)用(默認(rèn));sync 同步執(zhí)行;post 組件更新之后執(zhí)行
// flush 屬性在 watch 中用的不多,watchEffect中可能用到
}
);
// reactive 深層監(jiān)聽:不必開啟深度監(jiān)聽
watch(
message2,
(newVal, oldVal) => {
// 如果是引用類型,新值 和 舊值 是一樣的
console.log("reactive 深層監(jiān)聽&立刻執(zhí)行", newVal, oldVal);
},
{
// deep: true, // reactive 不必開啟深度監(jiān)聽,源碼已做了深層監(jiān)聽
// immediate: true,
}
);
// 若只想監(jiān)聽 reactive 深層中的單個屬性,(第一個參數(shù))引用類型可直接寫,否則使用函數(shù)形式
watch(
message2.foo, // 監(jiān)聽到 foo,foo是引用類型,直接寫就行
// () => message2.foo.bar, // 監(jiān)聽到 bar,需要用函數(shù)形式
(newVal, oldVal) => {
// 如果是引用類型,新值 和 舊值 是一樣的
console.log("reactive 監(jiān)聽深層中的單個屬性", newVal, oldVal);
}
);
二、源碼學(xué)習(xí)
由于源碼較多,這里不做截圖文章來源地址http://www.zghlxwxcb.cn/news/detail-653048.html
/**
*
* @vue/runtime-core/runtime-core.cjs.prod.js 搜索 function watch
*
* - watch(source, cb, options)
*
* - source 有很多種類型,reactive、ref、數(shù)組、函數(shù),所以先判斷類型,格式化source
* - ref 類型,直接把 value 取出來,賦值給 getter
* - reactive 類型,直接把整體賦值給 getter,deep 手動置為 true 即可(reactive已經(jīng)進(jìn)行了深度監(jiān)聽)
* - 數(shù)組類型,做遍歷,對每一項再判斷類型,分別處理完之后丟進(jìn)新數(shù)組返回
* - ref類型,返回.value
* - reactive類型,遞歸處理后返回
* - 函數(shù)的話,進(jìn)行加工
* - 函數(shù)類型
* - 判斷有沒有 cb
* - 有 cb 的話,同樣也是對函數(shù)做了加工賦值給 getter
* - 沒有 cb,走進(jìn) watchEffect(下一章)
*
* - deep處理:
* - cb、deep 若同時存在,即 有回調(diào)函數(shù) 且設(shè)置了 深度監(jiān)聽,進(jìn)行 traverse 遞歸深度監(jiān)聽(當(dāng)然是更耗時的)
*
* - flush處理:先初始化出 scheduler 調(diào)度器
* - sync 同步執(zhí)行,scheduler = job
* - post 組件更新后,將 job 通過 queuePostRenderEffect 函數(shù)處理后再賦值給 scheduler
* - 注意,源碼中看到 queuePostRenderEffect 這個函數(shù),一定表示是在組件更新之后再去執(zhí)行
* - pre 組件更新前,queueJob 處理 job 后賦值給 scheduler
*
* - ReactiveEffect 收集依賴更新:
* - 上面步驟 將 getter、scheduler處理好后作為參數(shù) 給到 ReactiveEffect 函數(shù)
* - ReactiveEffect 收集好依賴之后,有更新的話 就會觸發(fā) scheduler,也就是說會執(zhí)行 job
*
*
* - cb 存在
* - immediate 為 true 時,會立即調(diào)用一下 job
* - 內(nèi)部會先獲取到新值 newVal
* - 如果是第一次執(zhí)行,舊值 oldVal 會置為 undefined
* - (執(zhí)行完這里才會更新)然后 把新值賦值給舊值,為下一次使用準(zhǔn)備 (所以如果是對象,新舊值是相等的)
* - immediate 為 false 時,
* - 先給舊值做初始化,如 oldVal = '小滿'
* - 依賴如果更新,會觸發(fā) scheduler,執(zhí)行 job
* - job 內(nèi)新值 newVal = '小滿1'
* - 舊值 oldVal 不會走進(jìn) undefined,會等于原有的 oldVal = '小滿'
* - (執(zhí)行完這里才會更新)會把 oldVal = '小滿1'
*
*
*/
到了這里,關(guān)于Vue3 —— watch 監(jiān)聽器及源碼學(xué)習(xí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!