欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3中watch與watchEffect使用方法詳解

 更新時間:2025年09月03日 10:33:43   作者:時間sk  
在Vue中,watch和watchEffect都是用于觀察和響應(yīng)數(shù)據(jù)變化的工具,但它們在使用方式和功能上有一些顯著的區(qū)別,這篇文章主要介紹了Vue3中watch與watchEffect使用的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

一、監(jiān)聽器的基本概念

在Vue3中,watchwatchEffect都是用于監(jiān)聽數(shù)據(jù)變化并執(zhí)行副作用的API,但它們的使用方式和適用場景有所不同。

  • watch:需要顯式指定監(jiān)聽的數(shù)據(jù)源,惰性執(zhí)行(默認數(shù)據(jù)變化時才執(zhí)行),可以獲取新舊值
  • watchEffect:自動收集依賴,立即執(zhí)行,無法獲取舊值

二、watch的使用方法

2.1 基礎(chǔ)用法:監(jiān)聽單個ref數(shù)據(jù)

<template>
  <div>
    <p>計數(shù)器: {{ count }}</p>
    <button @click="count++">增加</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

// 創(chuàng)建響應(yīng)式數(shù)據(jù)
const count = ref(0)

// 監(jiān)聽count變化
// 第一個參數(shù):要監(jiān)聽的數(shù)據(jù)源
// 第二個參數(shù):回調(diào)函數(shù),接收新值和舊值
watch(count, (newValue, oldValue) => {
  console.log(`count從${oldValue}變?yōu)?{newValue}`)
})
</script>

2.2 監(jiān)聽多個數(shù)據(jù)源【監(jiān)聽多個數(shù)據(jù),用數(shù)組形式傳入】

import { ref, watch } from 'vue'

const firstName = ref('張')
const lastName = ref('三')

// 監(jiān)聽多個數(shù)據(jù),用數(shù)組形式傳入
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {
  console.log(`姓名從${oldFirst}${oldLast}變?yōu)?{newFirst}${newLast}`)
})

2.3 監(jiān)聽對象屬性【監(jiān)聽對象的某個屬性,使用getter函數(shù)】

import { reactive, watch } from 'vue'

const user = reactive({
  name: '張三',
  age: 20
})

// 監(jiān)聽對象的某個屬性,使用getter函數(shù)
watch(
  () => user.age,  // getter函數(shù),返回要監(jiān)聽的屬性
  (newAge, oldAge) => { console.log(`年齡從${oldAge}變?yōu)?{newAge}`)
  }
)

2.4 深度監(jiān)聽

當(dāng)監(jiān)聽對象或數(shù)組時,默認情況下watch不會監(jiān)聽內(nèi)部屬性變化,需要使用deep: true開啟深度監(jiān)聽:

import { ref, watch } from 'vue'

const user = ref({
  name: '張三',
  address: {
    city: '北京'
  }
})

// 深度監(jiān)聽對象內(nèi)部變化
watch(
  user,
  (newVal, oldVal) => { console.log('用戶信息變化:', newVal)},
  { deep: true }  // 開啟深度監(jiān)聽
)

// 修改深層屬性會觸發(fā)監(jiān)聽
user.value.address.city = '上海'

2.5 立即執(zhí)行

默認情況下,watch是惰性的,只有數(shù)據(jù)變化時才執(zhí)行。使用immediate: true可以讓它在初始化時立即執(zhí)行

watch(
  count,
  (newValue, oldValue) => {
    console.log(`count變化: ${newValue}`)
  },
  { immediate: true }  // 立即執(zhí)行
)

三、watchEffect的使用方法【可以不用指定監(jiān)聽的數(shù)據(jù)】

3.1 基礎(chǔ)用法

watchEffect會自動收集函數(shù)內(nèi)使用的響應(yīng)式數(shù)據(jù)作為依賴:

自動追蹤所有響應(yīng)式依賴, 每次依賴變更都會執(zhí)行此函數(shù)

<template>
  <div>
    <p>計數(shù)器: {{ count }}</p>
    <button @click="count++">增加</button>
  </div>
</template>

<script setup>
import { ref, watchEffect } from 'vue'

const count = ref(0)

// watchEffect會自動收集依賴
// 1. 初始化時立即執(zhí)行一次
// 2. 當(dāng)函數(shù)內(nèi)依賴的響應(yīng)式數(shù)據(jù)變化時重新執(zhí)行
watchEffect(  () => {console.log(`count的值是: ${count.value}`)}
)
</script>

3.2 停止監(jiān)聽

watchEffect返回一個停止函數(shù),調(diào)用它可以停止監(jiān)聽:

import { ref, watchEffect } from 'vue'

const count = ref(0)

// 獲取停止函數(shù)
const stop = watchEffect(() => {
  console.log(`count: ${count.value}`)
})

// 5秒后停止監(jiān)聽
setTimeout(() => {
  stop()
  console.log('已停止監(jiān)聽')
}, 5000)

3.3 清理副作用

watchEffect的回調(diào)函數(shù)可以返回一個清理函數(shù),在下次執(zhí)行前或停止監(jiān)聽時調(diào)用:

watchEffect((onInvalidate) => {
  // 模擬異步操作
  const timer = setTimeout(() => {
    console.log('異步操作完成')
  }, 1000)
  
  // 清理函數(shù),在下次執(zhí)行前或停止監(jiān)聽時調(diào)用
  onInvalidate(() => {
    clearTimeout(timer)
    console.log('清理定時器')
  })
})

四、watch與watchEffect的區(qū)別

特性watchwatchEffect
依賴收集需要顯式指定監(jiān)聽源自動收集函數(shù)內(nèi)的響應(yīng)式依賴
執(zhí)行時機默認惰性執(zhí)行(數(shù)據(jù)變化時)立即執(zhí)行,然后響應(yīng)式追蹤
新舊值可以獲取新值和舊值只能獲取新值
適用場景需要知道數(shù)據(jù)變化前后的值只需響應(yīng)數(shù)據(jù)變化,不需要舊值
控制粒度精確控制監(jiān)聽源自動追蹤所有依賴

五、高級用法

5.1 監(jiān)聽執(zhí)行時機控制

使用flush選項控制回調(diào)執(zhí)行時機:

watch(
  count,
  () => {
    // DOM更新后執(zhí)行
  },
  { flush: 'post' }  // 'pre'(默認) | 'post' | 'sync'
)

5.2 調(diào)試監(jiān)聽器

使用onTrackonTrigger選項調(diào)試依賴:

watch(
  count,
  () => {
    console.log('count變化了')
  },
  {
    onTrack(e) {
      console.log('依賴被追蹤:', e)
    },
    onTrigger(e) {
      console.log('監(jiān)聽器被觸發(fā):', e)
    }
  }
)

5.3 暫停與恢復(fù)監(jiān)聽(Vue3.5+)

Vue3.5+版本新增了暫停和恢復(fù)監(jiān)聽的功能:

const { pause, resume } = watch(count, () => {
  console.log('count變化了')
})

// 暫停監(jiān)聽
pause()

// 恢復(fù)監(jiān)聽
resume()

六、實戰(zhàn)示例

6.1 表單驗證(使用watch)

import { ref, watch } from 'vue'

const username = ref('')
const errorMessage = ref('')

// 監(jiān)聽用戶名變化進行驗證
watch(
  username,
  (newVal) => {
    if (newVal.length < 3) {
      errorMessage.value = '用戶名至少3個字符'
    } else {
      errorMessage.value = ''
    }
  },
  { immediate: true }  // 初始化時驗證
)

6.2 數(shù)據(jù)加載與清理(使用watchEffect)

import { ref, watchEffect } from 'vue'

const userId = ref(1)
const userData = ref(null)

watchEffect(async (onInvalidate) => {
  // 加載數(shù)據(jù)
  const controller = new AbortController()
  const signal = controller.signal
  
  try {
    const response = await fetch(`/api/user/${userId.value}`, { signal })
    userData.value = await response.json()
  } catch (error) {
    if (error.name !== 'AbortError') {
      console.error('加載失敗:', error)
    }
  }
  
  // 清理函數(shù),取消上一次請求
  onInvalidate(() => {
    controller.abort()
  })
})

七、總結(jié)

  • watch適合需要精細控制監(jiān)聽源、需要新舊值對比或需要延遲執(zhí)行的場景
  • watchEffect適合簡單的副作用處理,自動追蹤依賴,代碼更簡潔
  • 優(yōu)先使用watchEffect處理簡單邏輯,使用watch處理復(fù)雜場景
  • 注意清理副作用,避免內(nèi)存泄漏
  • 組件卸載時,同步創(chuàng)建的監(jiān)聽器會自動停止,異步創(chuàng)建的需要手動停止## 八、深入理解與高級技巧

7.1 watch監(jiān)聽reactive對象的注意事項

當(dāng)監(jiān)聽reactive創(chuàng)建的響應(yīng)式對象時,有一些特殊情況需要注意:

import { reactive, watch } from 'vue'

const user = reactive({
  name: '張三',
  age: 20
})

// 情況一:直接監(jiān)聽reactive對象
// 此時會自動開啟深度監(jiān)聽,無需設(shè)置deep: true
watch(user, (newVal, oldVal) => {
  console.log('用戶信息變化', newVal)
})

// 情況二:監(jiān)聽reactive對象的屬性
// 必須使用getter函數(shù),否則無法觸發(fā)監(jiān)聽
watch(
  () => user.age,  // 正確寫法
  (newAge) => {
    console.log('年齡變化:', newAge)
  }
)

// 錯誤寫法:直接監(jiān)聽屬性無法觸發(fā)
watch(user.age, () => {
  console.log('年齡變化') // 不會執(zhí)行
})

7.2 watchEffect的依賴追蹤細節(jié)

watchEffect的依賴追蹤是動態(tài)的,只追蹤函數(shù)執(zhí)行過程中實際訪問的響應(yīng)式數(shù)據(jù):

import { ref, watchEffect } from 'vue'

const a = ref(0)
const b = ref(0)

watchEffect(() => {
  console.log('watchEffect執(zhí)行')
  if (a.value > 5) {
    console.log('b的值:', b.value)
  }
})

// 初始執(zhí)行: 輸出 "watchEffect執(zhí)行"

a.value = 3  // 執(zhí)行: 輸出 "watchEffect執(zhí)行" (a被訪問)
b.value = 5  // 不執(zhí)行 (b未被訪問)
a.value = 6  // 執(zhí)行: 輸出 "watchEffect執(zhí)行" 和 "b的值: 5" (a和b都被訪問)
b.value = 10 // 執(zhí)行: 輸出 "watchEffect執(zhí)行" 和 "b的值: 10" (b現(xiàn)在被訪問了)

7.3 高級調(diào)試技巧

使用onTrackonTrigger選項可以幫助我們調(diào)試監(jiān)聽器的行為:

watch(
  count,
  () => {
    console.log('count變化了')
  },
  {
    onTrack(e) {
      // 當(dāng)依賴被追蹤時觸發(fā)
      console.log(`追蹤到依賴: ${e.target}的${e.key}屬性`)
    },
    onTrigger(e) {
      // 當(dāng)監(jiān)聽器被觸發(fā)時觸發(fā)
      console.log(`監(jiān)聽器觸發(fā)原因: ${e.type}`)
    }
  }
)

7.4 性能優(yōu)化策略

7.4.1 避免不必要的深度監(jiān)聽

深度監(jiān)聽會遞歸遍歷對象的所有屬性,對于大型對象會影響性能:

// 不推薦:深度監(jiān)聽大型對象
watch(largeObject, () => {
  // ...
}, { deep: true })

// 推薦:只監(jiān)聽需要的屬性
watch(
  () => largeObject.importantProperty,
  () => {
    // ...
  }
)

7.4.2 使用防抖/節(jié)流優(yōu)化頻繁觸發(fā)

對于輸入框等頻繁變化的場景,可以結(jié)合防抖/節(jié)流:

import { ref, watchEffect } from 'vue'
import { debounce } from 'lodash'

const searchInput = ref('')

// 使用防抖優(yōu)化搜索請求
const debouncedSearch = debounce(async (value) => {
  const results = await fetch(`/api/search?q=${value}`)
  // 處理結(jié)果
}, 300)

watchEffect(() => {
  debouncedSearch(searchInput.value)
})

八、常見問題與解決方案

8.1 監(jiān)聽器不觸發(fā)的常見原因

  1. 監(jiān)聽了非響應(yīng)式數(shù)據(jù)
// 錯誤:監(jiān)聽普通變量
let count = 0
watch(count, () => { /* 不會觸發(fā) */ })

// 正確:監(jiān)聽響應(yīng)式數(shù)據(jù)
const count = ref(0)
watch(count, () => { /* 會觸發(fā) */ })
  1. 直接修改數(shù)組索引或長度
const list = ref([1, 2, 3])

// 錯誤:直接修改索引
list.value[0] = 100  // 不會觸發(fā)監(jiān)聽

// 正確:使用數(shù)組方法或set
list.value.push(4)   // 會觸發(fā)
list.value.splice(0, 1, 100)  // 會觸發(fā)
  1. 監(jiān)聽對象新增屬性
const user = reactive({ name: '張三' })

// 錯誤:直接添加屬性
user.age = 20  // 默認不會觸發(fā)監(jiān)聽

// 正確:使用Vue.set或重新賦值
user.age = 20  // 在Vue3中,reactive對象新增屬性會觸發(fā)監(jiān)聽
// 或?qū)τ趓ef對象
user.value = { ...user.value, age: 20 }

8.2 watch與computed的選擇

場景推薦使用原因
數(shù)據(jù)轉(zhuǎn)換/計算computed緩存結(jié)果,更高效
數(shù)據(jù)變化時執(zhí)行異步操作watch適合處理副作用
需要知道數(shù)據(jù)變化前后的值watchcomputed無法獲取舊值
簡單的依賴追蹤watchEffect代碼更簡潔

九、完整實戰(zhàn)案例:搜索功能實現(xiàn)

下面是一個結(jié)合watch、watchEffect和computed的完整搜索功能實現(xiàn):

<template>
  <div class="search-container">
    <input 
      v-model="searchQuery" 
      placeholder="搜索..."
      @input="handleInput"
    >
    <div v-if="isSearching" class="loading">搜索中...</div>
    <div v-if="errorMessage" class="error">{{ errorMessage }}</div>
    <ul v-else-if="results.length">
      <li v-for="result in results" :key="result.id">{{ result.name }}</li>
    </ul>
    <div v-else-if="!isSearching && searchQuery">無結(jié)果</div>
  </div>
</template>

<script setup>
import { ref, watch, watchEffect, computed, onUnmounted } from 'vue'

// 響應(yīng)式數(shù)據(jù)
const searchQuery = ref('')
const results = ref([])
const isSearching = ref(false)
const errorMessage = ref('')
const debouncedQuery = ref('')

// 防抖處理
let timeoutId = null
const handleInput = () => {
  clearTimeout(timeoutId)
  timeoutId = setTimeout(() => {
    debouncedQuery.value = searchQuery.value
  }, 300)
}

// 使用watch處理搜索邏輯
watch(
  debouncedQuery,
  async (newQuery) => {
    if (!newQuery.trim()) {
      results.value = []
      return
    }
    
    isSearching.value = true
    errorMessage.value = ''
    
    try {
      const response = await fetch(`/api/search?q=${encodeURIComponent(newQuery)}`)
      if (!response.ok) throw new Error('搜索失敗')
      results.value = await response.json()
    } catch (err) {
      errorMessage.value = err.message
    } finally {
      isSearching.value = false
    }
  },
  { immediate: false }
)

// 使用watchEffect清理定時器
watchEffect((onInvalidate) => {
  // 組件卸載時清理定時器
  onInvalidate(() => {
    clearTimeout(timeoutId)
  })
})

// 清理函數(shù)
onUnmounted(() => {
  clearTimeout(timeoutId)
})
</script>

十、總結(jié)與最佳實踐

  1. 優(yōu)先使用watchEffect:當(dāng)你需要自動追蹤多個依賴,且不需要舊值時
  2. 使用watch的場景:需要明確監(jiān)聽源、需要舊值、需要延遲執(zhí)行或深度監(jiān)聽
  3. 性能考量
    • 避免對大型對象使用深度監(jiān)聽
    • 對頻繁變化的數(shù)據(jù)使用防抖/節(jié)流
    • 及時清理副作用,避免內(nèi)存泄漏
  4. 調(diào)試技巧:使用onTrack和onTrigger追蹤依賴問題
  5. 組件卸載:異步創(chuàng)建的監(jiān)聽器需要手動停止

通過合理選擇watch和watchEffect,并遵循最佳實踐,可以寫出更高效、更可維護的Vue3代碼。理解它們的內(nèi)部工作原理和適用場景,將幫助你在不同的業(yè)務(wù)需求中做出正確的技術(shù)選擇。## 十二、底層原理與實現(xiàn)機制

10.1 響應(yīng)式依賴收集流程

Vue3的監(jiān)聽器基于響應(yīng)式系統(tǒng)工作,其核心流程如下:

1. 當(dāng)watch/watchEffect執(zhí)行時,會創(chuàng)建一個"副作用函數(shù)"(effect)
2. 執(zhí)行副作用函數(shù),期間訪問的響應(yīng)式數(shù)據(jù)會被"追蹤"(track)
3. 響應(yīng)式數(shù)據(jù)變化時,會"觸發(fā)"(trigger)相關(guān)的副作用函數(shù)重新執(zhí)行

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  響應(yīng)式數(shù)據(jù)  │────?│  依賴追蹤器  │────?│ 副作用函數(shù)隊列 │
└─────────────┘     └─────────────┘     └─────────────┘
       ▲                                          │
       │                                          ▼
       └──────────────────────────────────────────┘
              (數(shù)據(jù)變化時觸發(fā)副作用執(zhí)行)

10.2 watch與watchEffect的內(nèi)部差異

// watch的簡化實現(xiàn)
function watch(source, callback, options) {
  // 創(chuàng)建getter函數(shù)
  const getter = isRef(source) 
    ? () => source.value 
    : typeof source === 'function' 
      ? source 
      : () => traverse(source);
  
  // 執(zhí)行副作用
  let oldValue = undefined;
  const effect = effectFn(() => getter(), {
    lazy: true, // 懶執(zhí)行,首次不觸發(fā)
    scheduler: () => { // 調(diào)度函數(shù)
      const newValue = getter();
      callback(newValue, oldValue);
      oldValue = newValue;
    }
  });
  
  // 初始化
  if (options.immediate) {
    callback(getter(), oldValue);
  } else {
    oldValue = effect();
  }
  
  return () => stop(effect);
}

// watchEffect的簡化實現(xiàn)
function watchEffect(effect, options) {
  const _effect = effectFn(effect, {
    lazy: false, // 立即執(zhí)行
    scheduler: queueJob, // 默認調(diào)度器
    ...options
  });
  
  return () => stop(_effect);
}

十一、API參數(shù)全解析

11.1 watch完整參數(shù)說明

// TypeScript類型定義
function watch<T>(
  source: WatchSource<T> | WatchSource<T>[],
  callback: WatchCallback<T>,
  options?: WatchOptions
): StopHandle

interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean  // 是否立即執(zhí)行,默認false
  deep?: boolean       // 是否深度監(jiān)聽,默認false
  flush?: 'pre' | 'post' | 'sync'  // 執(zhí)行時機,默認'pre'
  once?: boolean       // 是否只執(zhí)行一次,Vue3.4+,默認false
  onTrack?: (event: DebuggerEvent) => void  // 依賴追蹤時觸發(fā)
  onTrigger?: (event: DebuggerEvent) => void  // 觸發(fā)更新時觸發(fā)
}

11.2 flush選項詳解

取值執(zhí)行時機適用場景
‘pre’組件更新前執(zhí)行需要訪問更新前的DOM
‘post’組件更新后執(zhí)行需要訪問更新后的DOM
‘sync’同步執(zhí)行需要立即響應(yīng)數(shù)據(jù)變化
// 示例:在DOM更新后執(zhí)行
watch(
  count,
  () => {
    // 此時可以獲取到更新后的DOM
    console.log('DOM高度:', document.getElementById('content').offsetHeight)
  },
  { flush: 'post' }
)

十二、TypeScript高級用法

12.1 類型定義與推斷

import { ref, watch, reactive } from 'vue'

// 1. 監(jiān)聽ref
const count = ref<number>(0)
watch<number>(count, (newVal, oldVal) => {
  // newVal和oldVal都會被推斷為number類型
})

// 2. 監(jiān)聽reactive對象
interface User {
  name: string
  age: number
}
const user = reactive<User>({ name: '張三', age: 20 })
watch(
  () => user.age, 
  (newAge: number, oldAge: number) => {
    // 顯式指定類型
  }
)

// 3. 監(jiān)聽多個源
watch<[number, string]>(
  [count, () => user.name], 
  ([newCount, newName], [oldCount, oldName]) => {
    // 類型安全
  }
)

12.2 自定義監(jiān)聽器類型

import { ref, watch, WatchSource } from 'vue'

// 定義通用監(jiān)聽器類型
type CustomWatcher<T> = (
  source: WatchSource<T>,
  callback: (newVal: T, oldVal: T) => void
) => void

// 創(chuàng)建帶類型的監(jiān)聽器
const numberWatcher: CustomWatcher<number> = (source, callback) => {
  return watch(source, callback)
}

// 使用
const count = ref(0)
numberWatcher(count, (newVal, oldVal) => {
  // 類型安全
})

十三、調(diào)試與問題診斷

13.1 使用Vue DevTools調(diào)試

Vue DevTools提供了專門的監(jiān)聽器調(diào)試面板:

  1. 查看監(jiān)聽器列表:在"Components"面板中選擇組件,查看"Watchers"部分
  2. 觸發(fā)時機分析:使用"Timeline"面板記錄監(jiān)聽器觸發(fā)時間線
  3. 依賴可視化:查看每個監(jiān)聽器依賴的響應(yīng)式數(shù)據(jù)

13.2 常見問題診斷流程

監(jiān)聽器不觸發(fā)時的排查步驟:

1. 確認監(jiān)聽源是響應(yīng)式數(shù)據(jù)
   - 使用isRef/isReactive檢查
   - 確認不是解構(gòu)后的值

2. 檢查監(jiān)聽路徑是否正確
   - 對象屬性需使用getter函數(shù)
   - 數(shù)組需監(jiān)聽整個數(shù)組或使用正確索引

3. 驗證數(shù)據(jù)確實發(fā)生了變化
   - 使用console.log打印數(shù)據(jù)
   - 確認不是引用類型數(shù)據(jù)的內(nèi)部變化

4. 檢查是否需要深度監(jiān)聽
   - 對象/數(shù)組內(nèi)部變化需設(shè)置deep: true

5. 檢查是否有條件執(zhí)行問題
   - watchEffect中是否有條件語句導(dǎo)致依賴未被訪問

十四、性能優(yōu)化高級技巧

14.1 精確監(jiān)聽避免過度觸發(fā)

// 不好的做法:監(jiān)聽整個對象
watch(
  user,
  () => {
    // 即使無關(guān)屬性變化也會觸發(fā)
  },
  { deep: true }
)

// 好的做法:只監(jiān)聽需要的屬性
watch(
  () => ({ name: user.name, age: user.age }),
  ({ name, age }) => {
    // 只有這兩個屬性變化才觸發(fā)
  }
)

14.2 監(jiān)聽器防抖與節(jié)流

import { ref, watch } from 'vue'
import { debounce, throttle } from 'lodash'

// 防抖示例
const searchInput = ref('')
const debouncedSearch = debounce((value) => {
  // 搜索邏輯
}, 300)

watch(searchInput, debouncedSearch)

// 節(jié)流示例
const scrollPosition = ref(0)
const throttledScroll = throttle((position) => {
  // 滾動處理邏輯
}, 100)

watch(scrollPosition, throttledScroll)

14.3 大數(shù)據(jù)場景優(yōu)化

對于大型列表或復(fù)雜對象,使用shallowRefshallowReactive減少響應(yīng)式開銷:

import { shallowRef, watch } from 'vue'

// 大型數(shù)據(jù)使用shallowRef
const largeList = shallowRef([])

// 只監(jiān)聽引用變化,不監(jiān)聽內(nèi)部屬性
watch(largeList, () => {
  // 只有當(dāng)整個列表被替換時才觸發(fā)
})

十五、Vue2遷移指南

15.1 watch選項式API與組合式API對比

Vue2選項式APIVue3組合式API
javascript watch: { count(newVal, oldVal) { // 處理邏輯 } } javascript watch(count, (newVal, oldVal) => { // 處理邏輯 })
javascript watch: { 'user.name'(newVal) { // 監(jiān)聽嵌套屬性 } } javascript watch(() => user.name, (newVal) => { // 監(jiān)聽嵌套屬性 })
javascript watch: { user: { handler: () => {}, deep: true } } javascript watch(user, () => {}, { deep: true })

15.2 遷移注意事項

  1. this綁定:Vue3組合式API中沒有this,直接使用響應(yīng)式變量
  2. 深度監(jiān)聽:Vue3中reactive對象默認深度監(jiān)聽,ref對象需要設(shè)置deep: true
  3. 數(shù)組監(jiān)聽:Vue3中直接修改數(shù)組索引可以觸發(fā)監(jiān)聽(得益于Proxy)
  4. **watch方法∗∗:實例方法‘this.watch方法**:實例方法`this.watch方法:實例方法this.watch替換為watch`函數(shù)

十六、單元測試示例

使用Jest測試監(jiān)聽器行為:

import { ref, watch, watchEffect } from 'vue'
import { mount } from '@vue/test-utils'

describe('watch測試', () => {
  it('基本監(jiān)聽功能', async () => {
    const count = ref(0)
    const mockCallback = jest.fn()
    
    watch(count, mockCallback)
    
    // 初始狀態(tài)不觸發(fā)
    expect(mockCallback).not.toHaveBeenCalled()
    
    // 修改值后觸發(fā)
    count.value = 1
    await Promise.resolve() // 等待微任務(wù)完成
    
    expect(mockCallback).toHaveBeenCalledWith(1, 0)
  })
  
  it('watchEffect立即執(zhí)行', () => {
    const mockEffect = jest.fn()
    watchEffect(mockEffect)
    
    // 立即執(zhí)行
    expect(mockEffect).toHaveBeenCalled()
  })
})

十七、總結(jié):監(jiān)聽器選擇決策指南

面對不同場景,如何選擇合適的監(jiān)聽器API:

┌─────────────────────────────────────────────┐
│  需要知道數(shù)據(jù)變化前后的值                   │
│  ↓                                         │
│  需要明確指定監(jiān)聽源                         │
│  ↓              ┌───────────────┐          │
│  是────────────?│     watch     │?─────────┐
│  ↓              └───────────────┘          │
│  否                                         │
│  ↓              ┌───────────────┐          │
│  需要自動收集依賴 ─────────────?│watchEffect│?─────────┐
│                 └───────────────┘          │
│                                            │
│  需要緩存計算結(jié)果 ─────────────?│ computed  │
└─────────────────────────────────────────────┘

最終建議

  • 簡單場景優(yōu)先使用watchEffect,減少樣板代碼
  • 需要精確控制時使用watch
  • 純數(shù)據(jù)轉(zhuǎn)換使用computed
  • 始終考慮性能影響,避免過度監(jiān)聽
  • 復(fù)雜邏輯拆分到組合式函數(shù)中管理監(jiān)聽器

通過這一章節(jié)的補充,您現(xiàn)在應(yīng)該對Vue3的監(jiān)聽器系統(tǒng)有了全面且深入的理解,能夠在各種場景下選擇合適的API并編寫高效、可維護的代碼。

到此這篇關(guān)于Vue3中watch與watchEffect使用方法的文章就介紹到這了,更多相關(guān)Vue3 watch與watchEffect詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • uniapp一鍵打包H5的詳細步驟

    uniapp一鍵打包H5的詳細步驟

    uniapp如何打包到H5并成功發(fā)布,以及在打包過程中會遇到的坑如何解決,本文將一一講解,文中通過圖文結(jié)合的方式給大家講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2024-10-10
  • ElementUI年份范圍選擇器功能實現(xiàn)

    ElementUI年份范圍選擇器功能實現(xiàn)

    elementUI中有日期范圍組件,月份范圍選擇的,就是沒有年份范圍選擇的,需要加一個類似風(fēng)格的,下面這篇文章主要給大家介紹了關(guān)于ElementUI年份范圍選擇器功能實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • vue 插值 v-once,v-text, v-html詳解

    vue 插值 v-once,v-text, v-html詳解

    這篇文章主要介紹了vue 插值 v-once,v-text, v-html詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • vue中的v-if和v-show的區(qū)別詳解

    vue中的v-if和v-show的區(qū)別詳解

    這篇文章主要介紹了vue中的v-if和v-show的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具

    vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具

    這篇文章主要為大家介紹了vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具的踩坑分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • VUE預(yù)渲染及遇到的坑

    VUE預(yù)渲染及遇到的坑

    這篇文章主要介紹了VUE預(yù)渲染及遇到的坑,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • Vue 菜單欄點擊切換單個class(高亮)的方法

    Vue 菜單欄點擊切換單個class(高亮)的方法

    今天小編就為大家分享一篇Vue 菜單欄點擊切換單個class(高亮)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • Vue3使用router,params傳參為空問題

    Vue3使用router,params傳參為空問題

    這篇文章主要介紹了Vue3使用router,params傳參為空問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 詳解vue-template-admin三級路由無法緩存的解決方案

    詳解vue-template-admin三級路由無法緩存的解決方案

    這篇文章主要介紹了vue-template-admin三級路由無法緩存的解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • vue3?hook自動導(dǎo)入原理及使用

    vue3?hook自動導(dǎo)入原理及使用

    最近學(xué)習(xí)了hooks,特地寫一篇文章加深一下印象,下面這篇文章主要給大家介紹了關(guān)于vue3?hook自動導(dǎo)入原理及使用的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-10-10

最新評論