首頁  >  文章  >  web前端  >  vue3下的watch怎麼使用

vue3下的watch怎麼使用

WBOY
WBOY轉載
2023-05-17 12:14:262973瀏覽

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

    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 &#39;vue&#39;;
    const single = reactive({ count: 1, test: { a: 1, b: 2 } });
    const handleClick = function () {
      single.test.a++;
    };
    watch(
      single,
      (newValue, oldValue) => {
        console.log(&#39;值发生了变更&#39;, 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(&#39;值发生了变更&#39;, 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(&#39;值发生了变更&#39;, newValue, oldValue);
      },
      { deep: true, immediate: true }
    );

    如果兩個值同時發生變更,則會只觸發一次watch的回呼函數,而對於每個值的變更都會引發watch的回調函數。

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

    七,flush的設定

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

    回呼函數優先於DOM更新執行,監聽值變更時,flush預設為pre。這意味著,如果在回呼​​函數中有相關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 &#39;vue&#39;;
    const count = ref(1);
    const countDom = ref(null);
    const handleClick = function () {
      count.value++;
    };
    watch(
      count,
      (newValue, oldValue) => {
        console.log(&#39;---&#39;, countDom.value.textContent);
        console.log(&#39;值发生了变更&#39;, 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 &#39;vue&#39;;
    const count = ref(1);
    const countDom = ref(null);
    const handleClick = function () {
      count.value++;
    };
    watch(
      count,
      (newValue, oldValue) => {
        console.log(&#39;---&#39;, countDom.value.textContent);
        console.log(&#39;值发生了变更&#39;, newValue, oldValue);
      },
      { deep: true, flush: &#39;post&#39; }
    );
    </script>

    得到的結果:

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

    當回呼函數被呼叫時,DOM已經更新完成,此時取得到的DOM是經過資料變更後更新完成的DOM。

    以上是vue3下的watch怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除