首頁 > 軟體

vue3下watch的使用方法範例

2023-03-19 06:01:49

既然是資料監聽,監聽的是它的變化。那麼就需要能夠捕獲它的變更,於是監聽的資料必然要是響應式資料

watch(WatcherSource, Callback, [WatchOptions])
引數:
WatcherSource:想要監聽的響應式資料。
Callback:執行的回撥函數,入參(newValue,oldValue)。
[WatchOptions]:deep、immediate、flush可選。

對於WatchOptions的引數設定:

deep:當需要對物件等參照型別資料進行深度監聽時,設定deep: true,預設值是false。
immediate:預設情況下watch是惰性的,設定immediate: true時,watch會在初始化時立即執行回撥函數一次。
flush:控制回撥函數的執行時機,。它可設定為 pre、post 或 sync。
    pre:預設值,當監聽的值發生變更時,優先執行回撥函數(在dom更新之前執行)。
    post:dom更新渲染完畢後,執行回撥函數。
    sync:一旦監聽的值發生了變化,同步執行回撥函數(建議少用)。

一,監聽單個資料ref

const count = ref(1);
watch(count, (newValue, oldValue) => {
  console.log('值發生了變更', newValue, oldValue);
});

可以獲取到新值和舊值。

二,監聽參照型別資料ref:深度監聽

const count = ref({
  a: 1,
  b: 2
});
const handleClick = function () {
 count.value.a = 5;
};
watch(count, (newValue, oldValue) => {
  console.log('值發生了變更', newValue, oldValue);
});

這種情況下,我監聽的是整個陣列,它是參照資料型別,內部的某一項發生了變更並不會被監聽到。所以watch中的程式碼並沒有執行。

1,參照型別ref直接深度監聽

此時,就需要使用深度監聽:deep:true

const count = ref({
  a: 1,
  b: 2
});
const handleClick = function () {
  count.value.a = 5;
};
watch(
  count,
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true }
);

值發生了變更 Proxy {a: 5, b: 2} Proxy {a: 5, b: 2}

可以注意到的是,深度監聽的需要是這個參照資料型別自身,而不是其中的屬性。並且,他只能獲取到新值,而獲取不到舊的值。

2,參照型別ref深拷貝深度監聽

const count = ref({
  a: 1,
  b: 2
});
const handleClick = function () {
  count.value.a = 5;
};
watch(
  () => {
    return { ...count.value };
  },
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true }
);

這樣把watch的參照型別資料來源深拷貝一份,即可完成對新舊值得獲取:

值發生了變更 {a: 5, b: 2} {a: 1, b: 2}

三,監聽單個資料:reactive

const single = reactive({ count: 1, test: 2 });
const handleClick = function () {
  single.count++;
};
watch(
  () => single.count,
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { immediate: true }
);

這裡主要是() => single.count,監聽的是single中的count,只有這個屬性發生了變化才會觸發回撥函數。這種情況下是可以獲取到新舊值的。

四,監聽參照型別資料:reactive

<template>
  <div class="mine-box">
    <div ref="countDom">{{ single.count }}</div>
    <button @click="handleClick">按鈕</button>
  </div>
</template>

<script setup>
import { ref, reactive, watch } from 'vue';
const single = reactive({ count: 1, test: { a: 1, b: 2 } });
const handleClick = function () {
  single.test.a++;
};
watch(
  single,
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { immediate: true }
);
</script>

reactive的資料,用不用deep:true是沒有影響的,single中的一個屬性發生了變化,都能被監聽到,繼而執行回撥函數。

和三中有所不同的是,這種情況下是隻能獲取到新值的。

五,immediate: true

預設情況下watch是惰性的,當我們設定immediate: true時,watch會在初始化時立即執行回撥函數

const count = ref(1);
const handleClick = function () {
  count.value++;
};
watch(
  count,
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true, immediate: true }
);

六,監聽多個資料來源

const count = ref(1);
const double = ref(2);
const handleClick = function () {
  count.value++;
  double.value++;
};
watch(
  [count, double],
  (newValue, oldValue) => {
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true, immediate: true }
);

有一個值發生了變更,則會觸發watch,如果兩個值同時發生變更,同樣只是觸發一次watch的回撥函數。

如果想變更一格資料就觸發一次回撥,可以在兩個資料變更中間加下nextTick。

七,flush的設定

1,預設情況下在dom渲染完畢前呼叫回撥函數

預設情況下,flush的值是pre,當監聽的值發生變更時,優先執行回撥函數(在dom更新之前執行)。這就意味著,如果在回撥函數中有相關dom的操作,而引數裡面設定了immediate:true,則會報錯,因為這個時候dom還沒有被渲染,是獲取不到dom的。

接下來看下程式碼:

<template>
  <div class="mine-box">
    <div ref="countDom">{{ count }}</div>
    <button @click="handleClick">按鈕</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';
const count = ref(1);
const countDom = ref(null);
const handleClick = function () {
  count.value++;
};
watch(
  count,
  (newValue, oldValue) => {
    console.log('---', countDom.value.textContent);
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true }
);
</script>

得到的結果:

--- 1值發生了變更 2 1

可以看到,回撥函數中新的值已經變成了2,而獲取到的dom還是之前的。說明預設情況下,flush的值是pre,當有值變更時,是在dom更新之前觸發回撥函數的執行。

2,flush: 'post’在dom渲染完畢後執行回撥函數

<template>
  <div class="mine-box">
    <div ref="countDom">{{ count }}</div>
    <button @click="handleClick">按鈕</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';
const count = ref(1);
const countDom = ref(null);
const handleClick = function () {
  count.value++;
};
watch(
  count,
  (newValue, oldValue) => {
    console.log('---', countDom.value.textContent);
    console.log('值發生了變更', newValue, oldValue);
  },
  { deep: true, flush: 'post' }
);
</script>

得到的結果:

--- 2值發生了變更 2 1

可以看到,是在dom更新完畢之後才呼叫的回撥函數,這時候獲取到的dom是資料變更後更新完畢的dom。

八,總結

當使用ref建立的響應式資料時。

1,基本資料型別:可以直接監聽,可獲取新舊值。
2,參照資料型別:需要deep:true深度監聽,但是隻能獲取新值。要想獲取新舊值,要想獲取新舊值,需要監聽目標資料的深拷貝。

當使用reactive建立的響應式資料時。

1,基本資料型別:可以直接指定某個屬性進行監聽,可以獲取到新舊值。
2,參照資料型別:直接監聽建立的reactive物件,其中只要有屬性變更,都能被監聽到。但是它只能獲取到新值。
3,reactive建立的響應式資料,深度監聽設定是無效的,也就是deep:true/false都是能監聽到的。

deep引數

預設是false,只有使用ref建立的響應式參照型別的資料是,才啟用。才生效。

immediate引數

預設是false,初始化的時候不執行回撥函數。如果是true,初始化的時候就會執行一次回撥函數。

flush引數

預設是'pre',在dom渲染之前執行回撥函數,如果有immediate:true時,回撥函數有獲取dom操作,則會報錯,因為初始化時dom還沒生成。
設定成'post',則是在dom渲染完畢(監聽的資料變更後dom渲染完畢)後,再執行回撥函數。

總結

到此這篇關於vue3下watch的使用的文章就介紹到這了,更多相關vue3 watch使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com