最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue中的?watchEffect、watchAsyncEffect、watchPostEffect的區(qū)別對比分析

 更新時間:2025年10月10日 11:16:27   作者:北海-cherish  
在Vue中,watchEffect、watchAsyncEffect 和 watchPostEffect都是用于響應(yīng)式數(shù)據(jù)監(jiān)聽的API,但它們在執(zhí)行時機和行為上存在重要區(qū)別,接下來通過本文給大家介紹vue中的watchEffect、watchAsyncEffect、watchPostEffect的區(qū)別,感興趣的朋友一起看看吧

在 Vue 中,watchEffect、watchAsyncEffectwatchPostEffect 都是用于響應(yīng)式數(shù)據(jù)監(jiān)聽的 API,但它們在執(zhí)行時機和行為上存在重要區(qū)別:

  • watchEffect
    • 立即執(zhí)行傳入的函數(shù),并在函數(shù)中使用的響應(yīng)式數(shù)據(jù)變化時重新執(zhí)行
    • 默認在DOM 更新前執(zhí)行(前置執(zhí)行)
    • 適用于大多數(shù)需要立即響應(yīng)數(shù)據(jù)變化的場景
  • watchPostEffect
    • 行為與 watchEffect 類似,但回調(diào)函數(shù)會在DOM 更新后執(zhí)行(后置執(zhí)行)
    • 當(dāng)需要在數(shù)據(jù)變化并完成 DOM 更新后再執(zhí)行操作時使用(如獲取更新后的 DOM 尺寸)
    • 相當(dāng)于 watchEffect{ flush: 'post' } 配置
  • watchAsyncEffect
    • watchEffect 類似,但允許回調(diào)函數(shù)是異步的(返回 Promise)
    • Vue 會等待異步操作完成后再處理下一次觸發(fā),避免競態(tài)條件
    • 適用于需要在響應(yīng)式數(shù)據(jù)變化時執(zhí)行異步操作的場景

示例代碼對比:

// 立即執(zhí)行,DOM更新前觸發(fā)
watchEffect(() => {
  console.log('數(shù)據(jù)變化了,DOM更新前執(zhí)行')
})
// 立即執(zhí)行,DOM更新后觸發(fā)
watchPostEffect(() => {
  console.log('數(shù)據(jù)變化了,DOM更新后執(zhí)行')
  // 可以安全獲取更新后的DOM信息
})
// 處理異步操作
watchAsyncEffect(async () => {
  console.log('開始異步操作')
  await fetchData() // 異步操作
  console.log('異步操作完成')
})

簡單來說,選擇哪個 API 主要取決于:

  • 是否需要在 DOM 更新前還是后執(zhí)行
  • 回調(diào)函數(shù)是否包含異步操作

下面通過一個具體的示例來展示 watchEffectwatchAsyncEffectwatchPostEffect 的不同使用場景。這個示例包含一個計數(shù)器和一個列表,通過不同的監(jiān)聽方式展示它們的行為差異。

<template>
  <div class="container">
    <h3>計數(shù)器: {{ count }}</h3>
    <button @click="count++">增加</button>
    <div class="list-container">
      <p>列表項數(shù)量: {{ items.length }}</p>
      <ul ref="itemList">
        <li v-for="item in items" :key="item.id">{{ item.text }}</li>
      </ul>
    </div>
  </div>
</template>
<script setup>
import { ref, watchEffect, watchPostEffect, watchAsyncEffect } from 'vue'
// 響應(yīng)式數(shù)據(jù)
const count = ref(0)
const items = ref([])
const itemList = ref(null)
// 1. watchEffect: DOM更新前執(zhí)行 - 適合數(shù)據(jù)處理
watchEffect(() => {
  // 當(dāng)count變化時,添加新的列表項
  if (count.value > 0) {
    items.value.push({
      id: count.value,
      text: `項目 ${count.value}`
    })
  }
  console.log('watchEffect: 處理數(shù)據(jù),當(dāng)前列表長度:', items.value.length)
  // 此時獲取的DOM高度可能不準(zhǔn)確(DOM尚未更新)
  if (itemList.value) {
    console.log('watchEffect: 列表高度(可能不準(zhǔn)確):', itemList.value.offsetHeight)
  }
})
// 2. watchPostEffect: DOM更新后執(zhí)行 - 適合操作DOM
watchPostEffect(() => {
  // 確保在DOM更新后獲取列表高度
  if (itemList.value) {
    console.log('watchPostEffect: 列表高度(準(zhǔn)確):', itemList.value.offsetHeight)
  }
})
// 3. watchAsyncEffect: 處理異步操作 - 適合API調(diào)用等異步任務(wù)
watchAsyncEffect(async () => {
  if (count.value > 0) {
    console.log('watchAsyncEffect: 開始異步處理...')
    // 模擬API請求
    await new Promise(resolve => setTimeout(resolve, 500))
    console.log(`watchAsyncEffect: 異步處理完成,當(dāng)前計數(shù): ${count.value}`)
  }
})
</script>
<style>
.container {
  padding: 20px;
}
.list-container {
  margin-top: 20px;
  padding: 10px;
  border: 1px solid #ccc;
}
button {
  padding: 8px 16px;
  margin-top: 10px;
  cursor: pointer;
}
</style>

各API的使用場景解析:

  • watchEffect
    • 使用場景:數(shù)據(jù)處理、狀態(tài)轉(zhuǎn)換等不需要等待DOM更新的操作
    • 示例中:當(dāng)計數(shù)器變化時,立即更新列表數(shù)據(jù)
    • 特點:在DOM更新前執(zhí)行,此時如果嘗試獲取DOM屬性(如高度)可能得到舊值
  • watchPostEffect
    • 使用場景:需要操作DOM、獲取DOM尺寸或位置的場景
    • 示例中:在列表更新后準(zhǔn)確獲取其高度
    • 特點:在DOM更新后執(zhí)行,確保能獲取到最新的DOM狀態(tài)
  • watchAsyncEffect
    • 使用場景:需要執(zhí)行異步操作(如API請求、定時器等)的場景
    • 示例中:模擬在計數(shù)器變化后執(zhí)行異步任務(wù)
    • 特點:支持異步函數(shù),Vue會等待前一次異步操作完成后再處理下一次觸發(fā),避免競態(tài)問題

運行效果:

點擊"增加"按鈕后,控制臺會輸出類似以下內(nèi)容:

watchEffect: 處理數(shù)據(jù),當(dāng)前列表長度: 1
watchEffect: 列表高度(可能不準(zhǔn)確): 0
watchPostEffect: 列表高度(準(zhǔn)確): 21
watchAsyncEffect: 開始異步處理...
watchAsyncEffect: 異步處理完成,當(dāng)前計數(shù): 1

在 Vue 中,watchEffect、watchAsyncEffectwatchPostEffect 都會返回一個 停止函數(shù),通過調(diào)用這個函數(shù)可以手動停止監(jiān)聽。這是停止這些響應(yīng)式監(jiān)聽的統(tǒng)一方式,適用于所有這三個 API。

基本用法

調(diào)用監(jiān)聽 API 時,會得到一個函數(shù),執(zhí)行該函數(shù)即可停止監(jiān)聽:

import { watchEffect, watchAsyncEffect, watchPostEffect, ref } from 'vue'
const count = ref(0)
// 1. 停止 watchEffect
const stopEffect = watchEffect(() => {
  console.log('count 變化:', count.value)
})
// 2. 停止 watchAsyncEffect
const stopAsyncEffect = watchAsyncEffect(async () => {
  await someAsyncOperation()
  console.log('異步處理 count:', count.value)
})
// 3. 停止 watchPostEffect
const stopPostEffect = watchPostEffect(() => {
  console.log('DOM 更新后處理 count:', count.value)
})
// 需要停止時調(diào)用
stopEffect()      // 停止 watchEffect 監(jiān)聽
stopAsyncEffect() // 停止 watchAsyncEffect 監(jiān)聽
stopPostEffect()  // 停止 watchPostEffect 監(jiān)聽

實際場景示例

下面是一個組件中停止監(jiān)聽的完整示例,展示在組件卸載時自動停止監(jiān)聽(避免內(nèi)存泄漏):

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="count++">增加</button>
    <button @click="stopAll">停止所有監(jiān)聽</button>
  </div>
</template>
<script setup>
import { ref, watchEffect, watchAsyncEffect, watchPostEffect, onUnmounted } from 'vue'
const count = ref(0)
// 創(chuàng)建監(jiān)聽并保存停止函數(shù)
const stopEffect = watchEffect(() => {
  console.log('watchEffect: count =', count.value)
})
const stopAsyncEffect = watchAsyncEffect(async () => {
  await new Promise(resolve => setTimeout(resolve, 100))
  console.log('watchAsyncEffect: 異步處理 count =', count.value)
})
const stopPostEffect = watchPostEffect(() => {
  console.log('watchPostEffect: DOM更新后 count =', count.value)
})
// 手動停止所有監(jiān)聽的方法
const stopAll = () => {
  stopEffect()
  stopAsyncEffect()
  stopPostEffect()
  console.log('所有監(jiān)聽已停止')
}
// 組件卸載時自動停止(推薦做法)
onUnmounted(() => {
  stopEffect()
  stopAsyncEffect()
  stopPostEffect()
})
</script>

關(guān)鍵點說明

  • 自動停止時機
    • 在組件的 setup<script setup> 中創(chuàng)建的監(jiān)聽,會在組件卸載時 自動停止,無需手動處理。
    • 但如果是在非組件環(huán)境(如全局狀態(tài)管理)中創(chuàng)建的監(jiān)聽,則需要 手動調(diào)用停止函數(shù) 清理。
  • 停止后的行為
    • 調(diào)用停止函數(shù)后,響應(yīng)式數(shù)據(jù)變化時,對應(yīng)的監(jiān)聽回調(diào) 不會再執(zhí)行。
    • 對于 watchAsyncEffect,如果異步操作已經(jīng)開始,停止監(jiān)聽后 不會取消正在進行的異步操作,但后續(xù)的數(shù)據(jù)變化不會再觸發(fā)新的異步任務(wù)。
  • 最佳實踐
    • 組件內(nèi)的監(jiān)聽:通常無需手動停止,依賴 Vue 的自動清理。
    • 長時間運行的監(jiān)聽(如全局數(shù)據(jù)):在不需要時主動調(diào)用停止函數(shù),避免內(nèi)存泄漏。

在實際開發(fā)中,選擇 watchEffect、watchAsyncEffect 還是 watchPostEffect 主要取決于 操作的時機是否包含異步邏輯。以下是基于具體場景的選擇指南:

1. 優(yōu)先用watchEffect的場景

  • 核心特點:同步執(zhí)行,在 DOM 更新前觸發(fā)。
    • 適用于 不需要等待 DOM 更新無異步操作 的響應(yīng)式處理。
  • 典型場景:
    • 數(shù)據(jù)轉(zhuǎn)換/過濾:基于響應(yīng)式數(shù)據(jù)生成衍生數(shù)據(jù)
      • 例如:根據(jù)搜索關(guān)鍵詞過濾列表(只需處理數(shù)據(jù),無需操作 DOM)
const keywords = ref('')
const list = ref([...])
const filteredList = ref([])
watchEffect(() => {
  // 同步過濾數(shù)據(jù),DOM 更新前執(zhí)行
  filteredList.value = list.value.filter(item => 
    item.name.includes(keywords.value)
  )
})

狀態(tài)聯(lián)動:一個狀態(tài)變化觸發(fā)另一個狀態(tài)更新
例如:表單字段聯(lián)動(如“確認密碼”隨“密碼”字段變化而校驗)

const password = ref('')
const confirmPwd = ref('')
const pwdError = ref('')
watchEffect(() => {
  // 實時校驗,無需等待 DOM
  if (confirmPwd.value && confirmPwd.value !== password.value) {
    pwdError.value = '兩次密碼不一致'
  } else {
    pwdError.value = ''
  }
})

日志/調(diào)試:記錄數(shù)據(jù)變化(無需關(guān)心 DOM 狀態(tài))

2. 必須用watchPostEffect的場景

核心特點:同步執(zhí)行,在 DOM 更新后觸發(fā)。
適用于 需要操作更新后的 DOM 的場景(依賴 DOM 最新狀態(tài))。

典型場景:

獲取 DOM 尺寸/位置:如計算元素寬高、滾動位置
例如:列表渲染后自動滾動到底部

const messages = ref([])
const messageList = ref(null)
// 新增消息時,滾動到底部(依賴更新后的 DOM)
watchPostEffect(() => {
  if (messageList.value) {
    messageList.value.scrollTop = messageList.value.scrollHeight
  }
})

基于 DOM 狀態(tài)的樣式調(diào)整:如根據(jù)元素位置動態(tài)修改樣式

const activeEl = ref(null)
const elPosition = ref({ top: 0, left: 0 })
watchPostEffect(() => {
  if (activeEl.value) {
    // 獲取元素實際位置(DOM 更新后才準(zhǔn)確)
    const rect = activeEl.value.getBoundingClientRect()
    elPosition.value = { top: rect.top, left: rect.left }
  }
})

第三方庫 DOM 交互:如初始化依賴 DOM 結(jié)構(gòu)的插件(圖表、編輯器等)

const chartData = ref([])
const chartContainer = ref(null)
watchPostEffect(() => {
  // 確保容器 DOM 已更新,再初始化圖表
  if (chartContainer.value) {
    initChart(chartContainer.value, chartData.value)
  }
})

3. 必須用watchAsyncEffect的場景

  • 核心特點:支持異步函數(shù)(返回 Promise),會等待前一次異步完成后再處理下一次觸發(fā)(避免競態(tài)問題)。
    • 適用于 響應(yīng)式數(shù)據(jù)變化時需要執(zhí)行異步操作 的場景。
  • 典型場景:
  • API 請求:根據(jù)參數(shù)變化發(fā)起請求(自動處理競態(tài))
    • 例如:搜索框輸入變化時請求接口
const searchQuery = ref('')
const searchResult = ref([])
watchAsyncEffect(async () => {
  if (!searchQuery.value) {
    searchResult.value = []
    return
  }
  // 異步請求,Vue 會自動處理競態(tài)(后一次請求會等待前一次完成)
  const res = await fetch(`/api/search?query=${searchQuery.value}`)
  searchResult.value = await res.json()
})

帶延遲的異步操作:如防抖處理、定時器任務(wù)
例如:輸入停止 500ms 后執(zhí)行保存

const inputValue = ref('')
watchAsyncEffect(async () => {
  // 延遲 500ms 執(zhí)行,避免頻繁觸發(fā)
  await new Promise(resolve => setTimeout(resolve, 500))
  await saveToServer(inputValue.value) // 異步保存
})

依賴其他異步結(jié)果的操作:如多步異步流程

const userId = ref('')
const userPosts = ref([])
watchAsyncEffect(async () => {
  if (!userId.value) return
  // 先獲取用戶信息,再獲取用戶文章(依賴前一步異步結(jié)果)
  const user = await fetchUser(userId.value)
  const posts = await fetchPosts(user.id)
  userPosts.value = posts
})

總結(jié):選擇決策樹

  • 是否有異步操作?
    • 是 → 用 watchAsyncEffect
    • 否 → 看是否依賴 DOM 更新
  • 是否依賴 DOM 更新后的狀態(tài)?
    • 是 → 用 watchPostEffect
    • 否 → 用 watchEffect

通過遵循這個邏輯,可以準(zhǔn)確匹配 API 特性與實際需求,避免因時機錯誤導(dǎo)致的 BUG(如獲取到舊的 DOM 狀態(tài)、異步競態(tài)等)。

到此這篇關(guān)于vue中的 watchEffect、watchAsyncEffect、watchPostEffect的區(qū)別的文章就介紹到這了,更多相關(guān)vue watchEffect、watchAsyncEffect、watchPostEffect區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue項目中使用rem替換px的實現(xiàn)示例

    vue項目中使用rem替換px的實現(xiàn)示例

    移動端頁面適配,rem和vw適配方案,本文主要介紹了vue項目中使用rem替換px的實現(xiàn)示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 通過npm或yarn自動生成vue組件的方法示例

    通過npm或yarn自動生成vue組件的方法示例

    這篇文章主要介紹了通過npm或yarn自動生成vue組件的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • vue2 設(shè)置router-view默認路徑的實例

    vue2 設(shè)置router-view默認路徑的實例

    今天小編就為大家分享一篇vue2 設(shè)置router-view默認路徑的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue如何使用 Slot 分發(fā)內(nèi)容實例詳解

    vue如何使用 Slot 分發(fā)內(nèi)容實例詳解

    本篇文章主要介紹了vue如何使用 Slot 分發(fā)內(nèi)容實例詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • vue?css?相對路徑導(dǎo)入問題級踩坑記錄

    vue?css?相對路徑導(dǎo)入問題級踩坑記錄

    這篇文章主要介紹了vue?css?相對路徑導(dǎo)入問題級踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 詳解如何在 vue 項目里正確地引用 jquery 和 jquery-ui的插件

    詳解如何在 vue 項目里正確地引用 jquery 和 jquery-ui的插件

    本篇文章主要介紹了詳解如何在 vue 項目里正確地引用 jquery 和 jquery-ui的插件,具有一定的參考價值,有興趣的可以了解一下
    2017-06-06
  • Vue 兄弟組件通信的方法(不使用Vuex)

    Vue 兄弟組件通信的方法(不使用Vuex)

    本篇文章主要介紹了Vue 兄弟組件通信的方法(不使用Vuex),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Vue 同步異步存值取值實現(xiàn)案例

    Vue 同步異步存值取值實現(xiàn)案例

    這篇文章主要介紹了Vue 同步異步存值取值實現(xiàn)案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Vue使用Vue Elements實現(xiàn)文件預(yù)覽功能

    Vue使用Vue Elements實現(xiàn)文件預(yù)覽功能

    在現(xiàn)代 web 開發(fā)中,用戶與系統(tǒng)的交互體驗越來越重要,而文件上傳和文件預(yù)覽是最常見的交互場景之一,本文將詳細介紹如何在 Vue 項目中使用 Vue Elements 來實現(xiàn)文件預(yù)覽的功能,包括基本使用方法、常見實例、性能優(yōu)化以及樣式自定義等內(nèi)容,需要的朋友可以參考下
    2025-01-01
  • 一起來學(xué)習(xí)Vue的生命周期

    一起來學(xué)習(xí)Vue的生命周期

    這篇文章主要為大家詳細介紹了Vue的生命周期,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02

最新評論

泗阳县| 河池市| 蓝山县| 荆州市| 鄂州市| 宜兴市| 长寿区| 叙永县| 忻州市| 肇庆市| 三穗县| 陆良县| 类乌齐县| 云龙县| 瑞金市| 汶上县| 平和县| 英德市| 杭州市| 进贤县| 牙克石市| 通城县| 宜城市| 沁源县| 黄陵县| 长汀县| 多伦县| 图木舒克市| 黄龙县| 建宁县| 昌江| 刚察县| 揭阳市| 伊宁市| 确山县| 云龙县| 淮北市| 巴塘县| 杂多县| 孝义市| 抚宁县|