前端面經-VUE3篇(二)--vue3基礎知識(二)計算屬性(computed)、監聽屬性(Watch)

?一、計算屬性(computed)

計算屬性(Computed Properties)是 Vue 中一種特殊的響應式數據,它能基于已有的響應式數據動態計算出新的數據。

計算屬性有以下特性:

  • 自動緩存:只有當它依賴的響應式數據發生變化時,才會重新計算。

  • 響應式更新:依賴的數據變化后,會自動觸發計算屬性重新計算。

  • 簡化模板:在模板中使用計算屬性可以減少復雜邏輯,讓模板更清晰、易讀。

簡單來說:

計算屬性是基于其他響應式數據而自動計算得到的值,且具有緩存和響應式的特性。

1、計算屬性的基本用法

<script setup>
import { ref, computed } from 'vue'// 響應式數據
const firstName = ref('Tom')
const lastName = ref('Jerry')// 計算屬性(根據響應式數據動態計算)
const fullName = computed(() => {return `${firstName.value} ${lastName.value}`
})
</script><template><div>{{ fullName }}</div> <!-- 顯示:Tom Jerry -->
</template>

注意默認計算屬性是只讀的,但也可以定義成可寫。當你嘗試修改一個計算屬性時,你會收到一個運行時警告。只在某些特殊場景中你可能才需要用到“可寫”的屬性,你可以通過同時提供 getter 和 setter 來創建:

<script setup>
import { ref, computed } from 'vue'const firstName = ref('John')
const lastName = ref('Doe')const fullName = computed({// getterget() {return firstName.value + ' ' + lastName.value},// setterset(newValue) {// 注意:我們這里使用的是解構賦值語法[firstName.value, lastName.value] = newValue.split(' ')}
})
</script>

?現在當你再運行?fullName.value = 'John Doe'?時,setter 會被調用而?firstName?和?lastName?會隨之更新。

注意,computed()里面不接受任何的參數,我們看到里面有一個回調函數,這個回調函數本質上是getter函數

  • 之前版本(<3.4),這個 getter 函數沒有參數。

  • 從 3.4 開始,這個 getter 函數可以接受一個參數:就是上一次計算屬性的計算結果。

簡單來說:

如果需要,可以通過訪問計算屬性的 getter 的第一個參數來獲取計算屬性返回的上一個值:

<script setup>
import { ref, computed } from 'vue'const count = ref(2)// 這個計算屬性在 count 的值小于或等于 3 時,將返回 count 的值。
// 當 count 的值大于等于 4 時,將會返回滿足我們條件的最后一個值
// 直到 count 的值再次小于或等于 3 為止。
const alwaysSmall = computed((previous) => {if (count.value <= 3) {return count.value}return previous
})
</script>

?如果你正在使用可寫的計算屬性的話:

<script setup>
import { ref, computed } from 'vue'const count = ref(2)const alwaysSmall = computed({get(previous) {if (count.value <= 3) {return count.value}return previous},set(newValue) {count.value = newValue * 2}
})
</script>

?2、計算屬性與方法(methods)的詳細區別

兩者區別如下:

對比維度計算屬性(computed)方法(methods)
緩存機制有緩存,僅數據變化才重新計算無緩存,每次調用都會執行
調用方式不需要括號調用,像屬性一樣使用需要括號調用,明確為函數
適用場景基于響應式數據的計算處理事件或顯式調用的場景
性能開銷性能較高(緩存優化)性能較低(頻繁調用時)

計算屬性與方法性能差異分析

假設模板多次渲染對比:

  • 計算屬性

    <div>{{ doubleCount }}</div>
    <div>{{ doubleCount }}</div>
    <div>{{ doubleCount }}</div>
    
    • 只計算一次,緩存結果。

  • 方法調用

    <div>{{ getDoubleCount() }}</div>
    <div>{{ getDoubleCount() }}</div>
    <div>{{ getDoubleCount() }}</div>
    
    • 每次都調用一次,共調用3次,性能浪費。

因此,對于頻繁使用但數據不頻繁變化的場景,建議使用計算屬性

3、計算屬性什么時候不能用?

計算屬性適用于:

  • 同步、快速的計算邏輯

  • 無副作用的計算(純函數)。

計算屬性不適合:

  • 異步邏輯(如請求數據)。

  • 執行副作用(修改其他數據、DOM 操作)。

?二、監聽屬性

在 Vue 中,監聽屬性(Watch) 是一種響應式機制,用于監測響應式數據的變化:

  • 當你想在數據發生變化時執行某些邏輯(如發送請求、更新數據或執行某些副作用)時,就可以使用監聽屬性。

  • 監聽屬性通過 Vue 提供的 watch()watchEffect() 函數實現。

簡單來說:

監聽屬性讓你能夠對數據變化做出反應,執行一些副作用或異步操作。

1、監聽屬性的基本用法(watch)

<script setup>
import { ref, watch } from 'vue'const count = ref(0)// 監聽 count 的變化
watch(count, (newValue, oldValue) => {console.log(`count變化了:從${oldValue}到${newValue}`)
})
</script><template><button @click="count++">增加 ({{ count }})</button>
</template>

count 的值改變時,watch 會自動觸發,執行回調函數。

監聽多個數據:?

const firstName = ref('Tom')
const lastName = ref('Jerry')// 同時監聽 firstName 和 lastName
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {console.log(`名字變化了:${oldFirst} ${oldLast} => ${newFirst} ${newLast}`)
})

2、監聽屬性的參數與選項(高級用法)

🔹 監聽屬性的函數簽名:watch(source, callback, options)

  • source: 需要監聽的響應式數據,可以是單個或多個。可以是不同形式的“數據源”:它可以是一個 ref (包括計算屬性)、一個響應式對象、一個?getter 函數、或多個數據源組成的數組:

  • callback: 數據變化時執行的回調函數。

  • options: 可選參數,控制監聽器行為。

🔹 常用的監聽選項(options):

選項含義默認值
immediate是否立即執行一次監聽回調false
deep是否深度監聽對象內部屬性變化false
flush控制監聽器回調的執行時機'pre'

?深度監聽(deep)到底是什么?

  • 默認情況下,Vue 的監聽器只能監聽對象引用本身的變化(比如替換對象)。

  • 使用 deep: true 時,能監聽對象或數組內部屬性或元素的變化。

const user = ref({ name: 'Tom', age: 18 })// 默認淺監聽(只能監聽整個對象變化)
watch(user, () => {console.log('淺監聽:user變化了')
})user.value.age = 19 // ?不會觸發淺監聽(對象引用未變)
user.value = { name: 'Jerry', age: 19 } // ??觸發// 深度監聽(對象內部屬性變化也會觸發)
watch(user, () => {console.log('深監聽:user變化了')
}, { deep: true })user.value.age = 20 // ??觸發深度監聽

?監聽屬性的執行時機(flush)

flush 控制監聽回調的執行時機:

flush 值含義使用場景
pre默認值,組件更新之前執行大多數情況
post組件更新之后執行需要訪問更新后的DOM時
sync同步觸發,數據變化立即執行非常特殊情況

3、watch vs watchEffect 的區別

在 Vue 中,watch()watchEffect() 都用于響應式地執行一些副作用操作(如發起請求、改變 DOM),但二者的追蹤數據依賴方式不同:

特性watch()watchEffect()
如何追蹤依賴手動顯式指定要監聽的數據(明確)自動追蹤回調中訪問的數據(隱式)
首次執行默認不立即執行,需手動開啟自動立即執行一次
控制粒度精確控制監聽的數據項,控制更細自動追蹤所有訪問的響應式數據,更靈活
適用場景明確知道監聽什么數據變化數據依賴較多或復雜,更希望自動追蹤

?舉個簡單例子,監聽單個明確的數據:

const todoId = ref(1)
const data = ref(null)watch(todoId,async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()},{ immediate: true }
)

?特點:

  • todoId 被顯式聲明為監聽的源。

  • 回調函數只在明確的源數據(todoId)改變時觸發。

  • 必須用 { immediate: true } 來立即執行一次,否則首次不會執行。

1、?watchEffect() 如何簡化上面的例子?

const todoId = ref(1)
const data = ref(null)watchEffect(async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()
})

特點:

  • 自動立即執行一次,無需手動指定 { immediate: true }

  • 無需手動指定監聽源,回調函數內的所有響應式數據訪問(這里是 todoId.value)會自動被 Vue 跟蹤。

  • 一旦被跟蹤的數據變化(例如:todoId.value 改變),回調會自動再次執行。

?2、watchEffect() 的依賴跟蹤原理(關鍵):

watchEffect() 會自動追蹤回調函數在同步執行時訪問的所有響應式數據。
但有個重要提示:

如果回調是異步函數,那么只有在第一個 await 之前訪問的數據才會被追蹤!

watchEffect(async () => {console.log(todoId.value) // ? 被追蹤,因為在 await 之前訪問const response = await fetch('...')console.log(someOtherRef.value) // ? 不被追蹤,因為在 await 之后訪問
})

原因是:

  • Vue 只能追蹤同步執行階段訪問的數據。

  • 在異步操作完成后的回調內訪問的數據不會被 Vue 追蹤。

3、watchEffect() 在實際場景中的優勢:

優勢一:自動跟蹤多個數據源(不必手動指定):

假如你有多個響應式數據:

const firstName = ref('Tom')
const lastName = ref('Jerry')watchEffect(() => {console.log(`Name: ${firstName.value} ${lastName.value}`)
})Vue 自動監控 firstName 和 lastName。無論哪個改變,都會觸發回調函數。使用 watch() 則必須手動指定數據源:
watch([firstName, lastName], () => {console.log(`Name: ${firstName.value} ${lastName.value}`)
})
優勢二:更精細地跟蹤對象屬性(比深監聽高效):

假如你有復雜對象:

const user = ref({name: 'Tom',age: 20,address: { city: 'Shanghai', street: 'Main St' }
})watchEffect(() => {console.log(`User city: ${user.value.address.city}`)
})watchEffect() 只監聽了對象的部分屬性 (address.city),高效、精準。如果用深監聽 (watch(user, ..., { deep: true })),會監聽所有屬性的變化,性能可能較差。

4、什么時候用 watch()?什么時候用 watchEffect()

場景推薦方式理由
明確知道監聽的數據源? 使用 watch()明確指定,粒度精準
多個數據源或依賴復雜? 使用 watchEffect()自動跟蹤,代碼更簡潔、更靈活
動態數據請求或復雜副作用? watchEffect()自動監聽,省去手動指定煩惱

4、監聽屬性的常見使用場景

場景示例
數據變化請求API表單值變化時重新獲取數據
數據變化存儲數據自動保存用戶輸入
執行副作用數據變化時更新DOM或執行動畫

5、監聽屬性的注意事項?

  • 避免無限循環:

    watch(count, (val) => {count.value++ // ?? 無限循環,不要這樣做
    })
    
  • 不要監聽非響應式數據(監聽無效):

    const plain = { name: 'Tom' }
    watch(plain, () => {}) // ? 無效
    
  • 使用深監聽時注意性能問題(深監聽成本較高):

    watch(obj, () => {}, { deep: true }) // 謹慎使用
    

    注意,你不能直接偵聽響應式對象的屬性值,例如、

const obj = reactive({ count: 0 })// 錯誤,因為 watch() 得到的參數是一個 number
watch(obj.count, (count) => {console.log(`Count is: ${count}`)
})

?這里需要用一個返回該屬性的 getter 函數:

// 提供一個 getter 函數
watch(() => obj.count,(count) => {console.log(`Count is: ${count}`)}
)

6、副作用清理

在 Vue 中,所謂的副作用通常指:

  • 異步請求(如 API 請求)

  • 定時器 (setTimeoutsetInterval)

  • DOM 操作、監聽事件

  • 其他非純函數的邏輯

這些操作不是立即完成的,可能會在未來某個時刻繼續執行

?為什么需要副作用清理?

以 API 請求為例:假設我們有一個監聽器監聽 id:
watch(id, (newId) => {fetch(`/api/${newId}`).then(() => {console.log('請求完成,當前ID:', newId)})
})

可能的問題:

當你快速修改 id

  • 請求 1 (/api/1) 發出后,還未完成。

  • 請求 2 (/api/2) 立即發出。

  • 如果請求 2 的響應比請求 1 快,那么請求 1 的響應(較慢)回來時,結果是過時的,但還是會被處理。

我們想要的:

  • 當數據變化時,上一個異步請求應被取消或忽略,不再執行后續邏輯。

為了解決這個問題,Vue 提供了副作用清理機制

副作用清理函數 (onCleanup())

Vue 3.0 開始,Vue 提供了一個清理機制,稱為 onCleanup

watch(id, (newId, oldId, onCleanup) => {const controller = new AbortController()fetch(`/api/${newId}`, { signal: controller.signal }).then((res) => res.json()).then((data) => {console.log('請求結果:', data)})onCleanup(() => {controller.abort() // 取消上一個請求})
})

含義解釋:

  • 每次監聽的數據 (id) 變化時:

    • 先調用上一次注冊的 onCleanup 清理函數

    • 然后再執行新一次監聽回調。

  • 因此,上一次的異步請求會自動終止,避免過時請求的結果被錯誤處理。

?watchEffect() 中的副作用清理

watchEffect((onCleanup) => {const timer = setInterval(() => {console.log('定時執行')}, 1000)onCleanup(() => {clearInterval(timer) // 清理定時器})
})

原理相同:

  • 每次響應式數據變化重新執行副作用之前,先調用清理函數。

  • 確保副作用(定時器、請求等)不重疊,避免內存泄漏或數據錯亂。

從 Vue 3.5 版本開始,引入了新 API:onWatcherCleanup():?

import { watch, onWatcherCleanup } from 'vue'watch(id, (newId) => {const controller = new AbortController()fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {console.log('請求完成:', newId)})onWatcherCleanup(() => {controller.abort() // 取消上一個請求})
})

特點:

  • 不再需要第三個參數 onCleanup

  • 可以獨立地在監聽器或 watchEffect() 回調函數內調用清理函數。

?使用限制:

  • 必須在同步階段調用,不可放在 await 之后。

  • 因此,必須在異步操作之前注冊。

正確用法(同步調用):watch(id, (newId) => {const controller = new AbortController()onWatcherCleanup(() => controller.abort()) // 同步調用,正確!fetch(`/api/${newId}`, { signal: controller.signal })
})? 錯誤用法(異步調用):watch(id, async (newId) => {const controller = new AbortController()await someAsyncOperation()onWatcherCleanup(() => controller.abort()) // ? 錯誤!異步調用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904286.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904286.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904286.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[預備知識] 5. 優化理論(一)

優化理論 梯度下降&#xff08;Gradient Descent&#xff09; 數學原理與可視化 梯度下降是優化領域的基石算法&#xff0c;其核心思想是沿負梯度方向迭代更新參數。數學表達式為&#xff1a; θ t 1 θ t ? α ? θ J ( θ t ) \theta_{t1} \theta_t - \alpha \nabla…

大模型微調Fine-tuning:從概念到實踐的全面解析

目錄 引言 一、什么是大模型微調&#xff1f; 1.1 預訓練與微調的區別 1.2 微調的技術演進 二、為什么需要微調&#xff1f; 2.1 解決大模型的固有局限 2.2 微調的優勢 三、主流微調方法 3.1 全參數微調 3.2 參數高效微調&#xff08;PEFT&#xff09; 四、微調實踐指…

Docker 使用下 (二)

Docker 使用下 &#xff08;二&#xff09; 文章目錄 Docker 使用下 &#xff08;二&#xff09;前言一、初識Docker1.1 、Docker概述1.2 、Docker的歷史1.3 、Docker解決了什么問題1.4 、Docker 的優點1.5 、Docker的架構圖 二、鏡像三、容器四、數據卷4.1、數據卷的概念4.2 、…

洛谷P12238 [藍橋杯 2023 國 Java A] 單詞分類

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription] Copy from luogu. [Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis] 既然都是字符串前綴的問題了&#xff0c;那當然首先就應該想到 Trie \text{Trie} Trie 樹。 我們可…

pta作業中有啟發性的程序題

1 【知識點】&#xff1a;多態 函數接口定義&#xff1a; 以Student為基類&#xff0c;構建GroupA, GroupB和GroupC三個類 裁判測試程序樣例&#xff1a; #include<iostream> #include <string> using namespace std;/* 請在這里填寫答案 */int main() {const …

Scrapy框架之CrawlSpider爬蟲 實戰 詳解

CrawlSpider 是 Scrapy 框架中一個非常實用的爬蟲基類&#xff0c;它繼承自 Spider 類&#xff0c;主要用于實現基于規則的網頁爬取。相較于普通的 Spider 類&#xff0c;CrawlSpider 可以根據預定義的規則自動跟進頁面中的鏈接&#xff0c;從而實現更高效、更靈活的爬取。 Scr…

Glide 如何加載遠程 Base64 圖片

最近有個需求&#xff0c;后端給出的圖片地址并不是正常的 URL&#xff0c;而且需要一個接口去請求&#xff0c;但是返回的是 base64 數據流。這里不關心為啥要這么多&#xff0c;原因有很多&#xff0c;可能是系統的問題&#xff0c;也可能是能力問題。當然作為我們 Android 程…

004-nlohmann/json 快速認識-C++開源庫108杰

了解 nlohmann/json 的特點&#xff1b;理解編程中 “數據戰場”劃分的概念&#xff1b;迅速上手多種方式構建一個JSON對象&#xff1b; 1 特點與安裝 nlohmann/json 是一個在 github 長期霸占 “JSON” 熱搜版第1的CJSON處理庫。它的最大優點是與 C 標準庫的容器數據&#xf…

#基礎Machine Learning 算法(上)

機器學習算法的分類 機器學習算法大致可以分為三類&#xff1a; 監督學習算法 (Supervised Algorithms&#xff09;:在監督學習訓練過程中&#xff0c;可以由訓練數據集學到或建立一個模式&#xff08;函數 / learning model&#xff09;&#xff0c;并依此模式推測新的實例。…

正弦波、方波、三角波和鋸齒波信號發生器——Multisim電路仿真

目錄 Multisim使用教程說明鏈接 一、正弦波信號發生電路 1.1正弦波發生電路 電路組成 工作原理 振蕩頻率 1.2 正弦波發生電路仿真分析 工程文件鏈接 二、方波信號發生電路 2.1 方波發生電路可調頻率 工作原理 詳細過程 2.2 方波發生電路可調頻率/可調占空比 調節占空比 方波產生…

【AND-OR-~OR鎖存器設計】2022-8-31

緣由鎖存器11111111111-硬件開發-CSDN問答 重置1&#xff0c;不論輸入什么&#xff0c;輸出都為0&#xff1b; 重置0&#xff0c;輸入1就鎖住1 此時輸入再次變為0&#xff0c;輸出不變&#xff0c;為鎖住。

力扣-字符串-468 檢查ip

思路 考察字符串的使用&#xff0c;還有對所有邊界條件的檢查 spilt&#xff08;“\.”&#xff09;&#xff0c;toCharArray&#xff0c;Integer.parseInt() 代碼 class Solution {boolean checkIpv4Segment(String str){if(str.length() 0 || str.length() > 4) retur…

BC8 十六進制轉十進制

題目&#xff1a;BC8 十六進制轉十進制 描述 BoBo寫了一個十六進制整數ABCDEF&#xff0c;他問KiKi對應的十進制整數是多少。 輸入描述&#xff1a; 無 輸出描述&#xff1a; 十六進制整數ABCDEF對應的十進制整數&#xff0c;所占域寬為15。 備注&#xff1a; printf可以使用…

ARM子程序和棧

微處理器中的棧由棧指針指向存儲器中的棧頂來實現&#xff0c;當數據項入棧時&#xff0c;棧 指針向上移動&#xff0c;當數據項出棧時&#xff0c;棧指針向下移動。 實現棧時需要做出兩個決定&#xff1a;一是當數據項進棧時是向低位地址方向向上生 長&#xff08;圖a和圖b&a…

jwt身份驗證和基本的利用方式

前言 &#xff1a; 什么是jwt&#xff08;json web token&#xff09;&#xff1f; 看看英文單詞的意思就是 json形式的token 他的基本的特征 &#xff1a; 類似于這樣的 他有2個點 分割 解碼的時候會有三個部分 頭部 payload 對稱密鑰 這個就是對稱加密 頭部&am…

n8n工作流自動化平臺的實操:利用本地嵌入模型,完成文件內容的向量化及入庫

1.成果展示 1.1n8n的工作流 牽涉節點&#xff1a;FTP、Code、Milvus Vector Store、Embeddings OpenAI、Default Data Loader、Recursive Character Text Splitter 12.向量庫的結果 2.實操過程 2.1發布本地嵌入模型服務 將bge-m3嵌入模型&#xff0c;發布成滿足open api接口…

MATLAB人工大猩猩部隊GTO優化CNN-LSTM多變量時間序列預測

本博客來源于CSDN機器魚&#xff0c;未同意任何人轉載。 更多內容&#xff0c;歡迎點擊本專欄目錄&#xff0c;查看更多內容。 目錄 0 引言 1 數據準備 2 CNN-LSTM模型搭建 3 GTO超參數優化 3.1 GTO函數極值尋優 3.2 GTO優化CNN-LSTM超參數 3.3 主程序 4 結語 0 引言…

git項目遷移,包括所有的提交記錄和分支 gitlab遷移到gitblit

之前git都是全新項目上傳&#xff0c;沒有遷移過&#xff0c;因為遷移的話要考慮已有項目上的分支都要遷移過去&#xff0c;提交記錄能遷移就好&#xff1b;分支如果按照全新項目上傳的方式需要新git手動創建好老git已有分支&#xff0c;在手動一個一個克隆老項目分支代碼依次提…

Photo-SLAM論文理解、環境搭建、代碼理解與實測效果

前言&#xff1a;第一個解耦式Photo-SLAM&#xff0c;亮點和效果。 參考&#xff1a;https://zhuanlan.zhihu.com/p/715311759 全網最細PhotoSLAM的conda環境配置教程&#xff0c;拒絕環境污染&#xff01;&#xff01;-CSDN博客 1. 環境搭建 硬件&#xff1a;RTX 4090D wi…

如何使用VSCode編寫C、C++和Python程序

一、首先準備好前期工作。如下載安裝Python、VSCode、一些插件等。寫代碼之前需要先創建文件夾和文件。 二、將不同語言寫的代碼放在不同的文件夾中&#xff0c;注意命名時不要使用中文。 三、打開VSCode&#xff0c;點擊“文件”->“打開文件夾”->“daimalainxi”->…