文章目錄
- 1. 前言
- 2. 常規用法
- 3. 監聽對象和route變化
- 4. 使用場景
- 4.1 即時表單驗證
- 4.2 搜索聯想功能
- 4.3 數據變化聯動處理
- 5. watchEffect詳解
- 5-1 基本概念
- 5-2 核心用法
- 基礎示例:自動響應依賴變化
- 處理異步副作用
- 停止監聽與清理副作用
- 5-3 高級場景應用
- 監聽多個響應式依賴
- 處理 DOM 副作用
- 6. watch與watchEffect的對比
- 選擇建議:
1. 前言
在 Vue3 中,watch 是一個獨立的函數,用于響應式地監聽數據變化并執行回調。與 Vue2 的選項式 API 不同,Vue3 的 watch 主要在 Composition API 中使用,需要從 @vue/composition-api
或 Vue3 核心包中導入。它接收三個參數:監聽的數據源、回調函數和可選的配置對象。
Vue3 的 watch 具有以下特點:
- 更靈活的監聽方式,支持監聽 ref、reactive 對象和函數返回值
- 明確的依賴聲明,避免依賴收集問題
- 更強大的配置選項,如深度監聽、立即執行等
2. 常規用法
在 Vue3 中使用 watch 需要先導入相關函數,通常在 setup 函數中使用。watch 第一個參數可以是 ref 類型的數據、響應式對象的屬性,或者一個返回值的函數。回調函數接收新值和舊值作為參數。
<template><div class="home_box"><h1>{{ total }}</h1><button @click="handleAddTotal">增加</button></div>
</template><script>
import { ref, watch } from 'vue';export default {name: 'Home',setup() {const total = ref(0);// 常規監聽 ref 類型數據watch(total, (newValue, oldValue) => {console.log('舊值:', oldValue);console.log('新值:', newValue);});const handleAddTotal = () => {total.value++;};return {total,handleAddTotal};}
}
</script>
3. 監聽對象和route變化
Vue3 的 watch 可以監聽多種類型的數據,包括響應式對象、嵌套屬性和路由變化。對于對象類型的監聽,需要注意深度監聽的配置;對于路由變化,需要使用特定的監聽方式。
<template><div class="home_box"><!-- 頁面內容 --></div>
</template><script>
import { ref, reactive, watch } from 'vue';
import { useRoute } from 'vue-router';export default {name: 'Home',setup() {// 基本類型const aaa = ref(0);// 響應式對象const state = reactive({bbb: 0,ccc: {c1: 0,c2: 0},ddd: {d1: 0,d2: {d21: 0}}});// 獲取路由實例const route = useRoute();// 監聽基本類型watch(aaa, (newValue, oldValue) => {console.log('aaa 舊值:', oldValue);console.log('aaa 新值:', newValue);});// 監聽基本類型,初始化立即執行watch(() => state.bbb, (newValue, oldValue) => {console.log('bbb 舊值:', oldValue);console.log('bbb 新值:', newValue);}, { immediate: true });// 監聽對象,需要深度監聽watch(() => state.ccc, (newValue, oldValue) => {console.log('ccc 舊值:', oldValue);console.log('ccc 新值:', newValue);}, { deep: true });// 監聽對象嵌套屬性watch(() => state.ddd.d2.d21, (newValue, oldValue) => {console.log('d21 舊值:', oldValue);console.log('d21 新值:', newValue);});// 監聽路由變化watch(() => route.path, (newPath, oldPath) => {console.log('路由舊路徑:', oldPath);console.log('路由新路徑:', newPath);});return {aaa,state};}
}
</script>
4. 使用場景
Vue3 的 watch 在很多場景中都有重要應用,特別是在需要響應數據變化并執行副作用的場景中。以下是幾個典型使用場景:
4.1 即時表單驗證
<template><div class="home_box"><input type="text" v-model="username"><div v-if="validationError" class="error-message">{{ validationError }}</div></div>
</template><script>
import { ref, watch } from 'vue';export default {name: 'FormValidation',setup() {const username = ref('');const validationError = ref('');// 監聽輸入框內容變化,即時驗證watch(username, (newValue) => {if (newValue.length < 3) {validationError.value = '用戶名至少需要3個字符';} else if (newValue.length > 20) {validationError.value = '用戶名不能超過20個字符';} else {validationError.value = '';}});return {username,validationError};}
}
</script>
4.2 搜索聯想功能
<template><div class="home_box"><input type="text" v-model="searchKeyword"><div v-if="searchResults.length > 0" class="suggestions"><div v-for="result in searchResults" :key="result">{{ result }}</div></div></div>
</template><script>
import { ref, watch } from 'vue';export default {name: 'SearchSuggestions',setup() {const searchKeyword = ref('');const searchResults = ref([]);// 監聽搜索關鍵詞變化,延遲發送請求let searchTimeout;watch(searchKeyword, (newValue) => {if (newValue.length < 2) {searchResults.value = [];return;}// 防抖處理,避免頻繁請求clearTimeout(searchTimeout);searchTimeout = setTimeout(() => {// 模擬API請求searchResults.value = [`${newValue} 相關結果1`,`${newValue} 相關結果2`,`${newValue} 相關結果3`];}, 500);});return {searchKeyword,searchResults};}
}
</script>
4.3 數據變化聯動處理
<template><div class="home_box"><div><label>寬度:</label><input type="number" v-model="width"></div><div><label>高度:</label><input type="number" v-model="height"></div><div>面積:{{ area }}</div></div>
</template><script>
import { ref, watch } from 'vue';export default {name: 'DimensionCalculator',setup() {const width = ref(10);const height = ref(20);const area = ref(0);// 監聽寬度和高度變化,計算面積watch([width, height], ([newWidth, newHeight]) => {area.value = newWidth * newHeight;});return {width,height,area};}
}
</script>
5. watchEffect詳解
5-1 基本概念
watchEffect
是 Vue3 中 Composition API 提供的響應式副作用監聽函數,與 watch
的主動監聽不同,它會自動追蹤回調函數中使用的響應式依賴,當依賴變化時觸發回調。其核心特點包括:
- 自動依賴收集:無需顯式聲明監聽目標,回調內使用的響應式數據會被自動追蹤
- 初始化立即執行:默認在組件掛載后立即執行一次回調,用于處理初始依賴的副作用
- 簡潔的語法:適用于依賴多個響應式數據的場景,避免重復聲明監聽源
5-2 核心用法
基礎示例:自動響應依賴變化
<template><div class="home_box"><h3>計數器:{{ count }}</h3><h3>翻倍值:{{ doubleCount }}</h3><button @click="count++">+1</button></div>
</template><script>
import { ref, watchEffect } from 'vue';export default {name: 'WatchEffectDemo',setup() {const count = ref(0);const doubleCount = ref(0);// watchEffect 會自動監聽 count 的變化watchEffect(() => {console.log('依賴變化觸發回調');doubleCount.value = count.value * 2;});// 初始化時立即輸出// 控制臺打印:依賴變化觸發回調return {count,doubleCount};}
}
</script>
處理異步副作用
<template><div class="home_box"><input v-model="searchText" placeholder="搜索..."><div v-if="loading">加載中...</div><div v-else-if="searchResults.length > 0"><ul><li v-for="item in searchResults" :key="item">{{ item }}</li></ul></div><div v-else>無搜索結果</div></div>
</template><script>
import { ref, watchEffect } from 'vue';export default {name: 'SearchEffect',setup() {const searchText = ref('');const searchResults = ref([]);const loading = ref(false);watchEffect(async onInvalidate => {// 當 searchText 變化時,先清除之前的定時器let timeout;onInvalidate(() => clearTimeout(timeout));if (searchText.value.length < 2) {searchResults.value = [];return;}loading.value = true;// 模擬異步搜索timeout = setTimeout(async () => {try {// 模擬API請求const response = await new Promise(resolve => {setTimeout(() => {resolve([`${searchText.value} 結果1`,`${searchText.value} 結果2`,`${searchText.value} 結果3`]);}, 500);});searchResults.value = response;} catch (error) {console.error('搜索失敗', error);} finally {loading.value = false;}}, 300);});return {searchText,searchResults,loading};}
}
</script>
停止監聽與清理副作用
<template><div class="home_box"><button @click="toggleWatch">{{ isWatching ? '停止監聽' : '開始監聽' }}</button><div>計數器:{{ count }}</div></div>
</template><script>
import { ref, watchEffect } from 'vue';export default {name: 'WatchEffectControl',setup() {const count = ref(0);const isWatching = ref(true);let watcher = null;// 條件性創建 watchEffectconst toggleWatch = () => {if (isWatching.value) {// 啟動監聽watcher = watchEffect(() => {console.log('監聽中,count:', count.value);});} else {// 停止監聽watcher && watcher();}isWatching.value = !isWatching.value;};return {count,isWatching,toggleWatch};}
}
</script>
5-3 高級場景應用
監聽多個響應式依賴
<template><div class="home_box"><div><label>寬度:</label><input type="number" v-model="width"></div><div><label>高度:</label><input type="number" v-model="height"></div><div>面積:{{ area }}</div><div>周長:{{ perimeter }}</div></div>
</template><script>
import { ref, watchEffect } from 'vue';export default {name: 'DimensionCalculator',setup() {const width = ref(10);const height = ref(20);const area = ref(0);const perimeter = ref(0);// 同時監聽 width 和 height 的變化watchEffect(() => {area.value = width.value * height.value;perimeter.value = 2 * (width.value + height.value);});return {width,height,area,perimeter};}
}
</script>
處理 DOM 副作用
<template><div class="home_box" ref="container"><h3>滾動位置:{{ scrollY }}</h3></div>
</template><script>
import { ref, onMounted, watchEffect } from 'vue';export default {name: 'ScrollEffect',setup() {const container = ref(null);const scrollY = ref(0);onMounted(() => {// 監聽容器滾動事件watchEffect(onInvalidate => {if (!container.value) return;const handleScroll = () => {scrollY.value = container.value.scrollTop;};container.value.addEventListener('scroll', handleScroll);// 組件卸載或依賴變化時清理事件onInvalidate(() => {container.value.removeEventListener('scroll', handleScroll);});});});return {container,scrollY};}
}
</script>
6. watch與watchEffect的對比
特性 | watch | watchEffect |
---|---|---|
依賴聲明方式 | 顯式指定監聽的數據源(ref、reactive 屬性、函數返回值) | 隱式收集回調函數中使用的響應式依賴 |
初始化執行 | 默認不執行,需通過 immediate: true 配置 | 初始化時立即執行一次 |
回調參數 | 接收新值和舊值 (newValue, oldValue) | 不接收參數,通過閉包訪問最新值 |
適用場景 | 監聽特定數據的變化,需要獲取新舊值對比 | 處理與多個響應式數據相關的副作用,無需明確依賴 |
性能優化 | 可精確控制監聽目標,避免無效觸發 | 依賴收集可能包含不必要的響應式數據,需注意副作用清理 |
語法復雜度 | 語法相對繁瑣,需聲明監聽源和配置項 | 語法簡潔,適合快速實現響應式副作用 |
異步處理 | 更適合處理需要等待特定數據變化的異步操作 | 適合處理隨依賴變化自動更新的異步副作用(如API請求、DOM操作) |
選擇建議:
- 使用 watch:
- 需要明確知道監聽的數據源
- 只在特定數據變化時執行回調
- 需要獲取變化前后的新舊值對比
- 使用 watchEffect:
- 處理與多個響應式數據相關的副作用
- 初始化時需要立即執行一次副作用
- 希望以更簡潔的方式實現響應式邏輯
// 場景:監聽用戶登錄狀態并請求用戶數據
setup() {const isLoggedIn = ref(false);const userData = ref(null);// 使用 watch 監聽登錄狀態變化watch(isLoggedIn, (newVal) => {if (newVal) {fetchUserData(); // 只在登錄狀態變化時請求}});// 使用 watchEffect 自動響應視圖更新watchEffect(() => {document.title = `用戶狀態: ${isLoggedIn.value ? '已登錄' : '未登錄'}`;});
}
本次分享就到這兒啦,我是鵬多多,如果您看了覺得有幫助,歡迎評論,關注,點贊,轉發,我們下次見~
往期文章
- vue中ref的詳解以及react的ref對比
- css使用aspect-ratio制作4:3和9:16和1:1等等比例布局
- Web前端頁面開發阿拉伯語種適配指南
- flutter-使用extended_image操作圖片的加載和狀態處理以及緩存和下載
- flutter-制作可縮放底部彈出抽屜評論區效果
- flutter-實現Tabs吸頂的PageView效果
- Vue2全家桶+Element搭建的PC端在線音樂網站
- 助你上手Vue3全家桶之Vue3教程
- 超詳細!vue組件通信的10種方式
- 超詳細!Vuex手把手教程
- 使用nvm管理node.js版本以及更換npm淘寶鏡像源
- vue中利用.env文件存儲全局環境變量,以及配置vue啟動和打包命令
個人主頁
- CSDN
- GitHub
- 掘金