Vue監(jiān)視數(shù)據(jù)的原理和set()的使用方法示例
前言
在 Vue 中,Vue.set()(或 this.$set())是用于解決響應(yīng)式數(shù)據(jù)更新檢測的重要方法,其底層與 Vue 的數(shù)據(jù)監(jiān)視原理緊密相關(guān)。以下從使用場景和實(shí)現(xiàn)原理兩方面詳細(xì)說明:
一、Vue.set () 的使用場景與用法
1. 為什么需要 Vue.set ()?
Vue 的響應(yīng)式系統(tǒng)通過 Object.defineProperty(Vue 2)或 Proxy(Vue 3)實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽,但存在限制:
- 無法檢測對象新增的屬性或刪除的屬性;
- 無法檢測數(shù)組通過索引修改元素或修改數(shù)組長度的操作。
此時,直接修改數(shù)據(jù)不會觸發(fā)視圖更新,需要用 Vue.set() 強(qiáng)制觸發(fā)響應(yīng)式更新。
2. 用法
- 語法:
// 全局方法 Vue.set(target, propertyName/index, value) // 實(shí)例方法(組件內(nèi)) this.$set(target, propertyName/index, value)
- 參數(shù):
target:需要修改的響應(yīng)式對象或數(shù)組(必須是已被 Vue 響應(yīng)式系統(tǒng)劫持的對象);propertyName/index:新增 / 修改的屬性名(對象)或索引(數(shù)組);value:對應(yīng)的值。
3. 典型場景
給對象新增響應(yīng)式屬性:
data() { return { user: { name: '張三' } } }, methods: { addAge() { // 直接新增屬性,視圖不會更新 this.user.age = 20; // 無效 // 使用 $set,視圖會更新 this.$set(this.user, 'age', 20); // 有效 } }修改數(shù)組的指定元素:
data() { return { list: ['蘋果', '香蕉'] } }, methods: { updateItem() { // 直接通過索引修改,視圖不會更新 this.list[1] = '橙子'; // 無效 // 使用 $set,視圖會更新 this.$set(this.list, 1, '橙子'); // 有效 } }
二、Vue 監(jiān)視數(shù)據(jù)的原理
Vue 實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式的核心是對數(shù)據(jù)進(jìn)行劫持,并在數(shù)據(jù)變化時通知依賴更新視圖。不同 Vue 版本的實(shí)現(xiàn)方式略有差異:
1. Vue 2 的響應(yīng)式原理(Object.defineProperty)
初始化劫持:
當(dāng)組件初始化時,Vue 會遍歷data中的所有屬性,通過Object.defineProperty為每個屬性添加getter和setter:getter:當(dāng)屬性被訪問時觸發(fā),用于收集依賴(記錄哪些視圖 / 計算屬性依賴該數(shù)據(jù))。setter:當(dāng)屬性被修改時觸發(fā),用于通知依賴更新(觸發(fā)視圖重新渲染)。
局限性:
- 只能劫持初始化時已存在的屬性,新增屬性默認(rèn)沒有
getter/setter,因此無法被監(jiān)測。 - 數(shù)組的
length修改和索引賦值不會觸發(fā)setter(Vue 對數(shù)組的 7 個方法進(jìn)行了重寫,如push、splice等,這些方法會觸發(fā)更新,但直接修改索引 / 長度不會)。
- 只能劫持初始化時已存在的屬性,新增屬性默認(rèn)沒有
2. Vue 3 的響應(yīng)式原理(Proxy)
初始化劫持:
Vue 3 使用 ES6 的Proxy對data對象進(jìn)行代理,生成一個代理對象(Proxy)。Proxy可以攔截對象的所有操作(包括新增屬性、刪除屬性、索引訪問等),從而解決了 Vue 2 的局限性。優(yōu)勢:
- 能監(jiān)測新增屬性(
proxy.xxx = value會被set攔截); - 能監(jiān)測刪除屬性(
delete proxy.xxx會被deleteProperty攔截); - 能監(jiān)測數(shù)組索引修改和長度變化(通過
set攔截)。
- 能監(jiān)測新增屬性(
三、Vue.set () 的底層實(shí)現(xiàn)邏輯
Vue.set() 的核心作用是手動為數(shù)據(jù)添加響應(yīng)式能力,并觸發(fā)更新:
對于對象:
- 檢查目標(biāo)對象是否為響應(yīng)式對象(是否有
__ob__標(biāo)識,Vue 內(nèi)部用于標(biāo)記響應(yīng)式對象)。 - 若屬性已存在,則直接修改值并觸發(fā)
setter。 - 若屬性不存在,則通過
Object.defineProperty(Vue 2)或Proxy的set攔截(Vue 3)為新屬性添加響應(yīng)式,并手動觸發(fā)依賴更新。
- 檢查目標(biāo)對象是否為響應(yīng)式對象(是否有
對于數(shù)組:
- 調(diào)用數(shù)組的
splice方法(Vue 已重寫該方法,會觸發(fā)更新),通過splice(index, 1, value)實(shí)現(xiàn)元素修改,從而觸發(fā)視圖更新。
- 調(diào)用數(shù)組的
總結(jié)
- Vue.set () 的作用:解決 Vue 響應(yīng)式系統(tǒng)無法檢測 “對象新增屬性”“數(shù)組索引修改” 等操作的問題,強(qiáng)制為數(shù)據(jù)添加響應(yīng)式并觸發(fā)視圖更新。
- 監(jiān)視數(shù)據(jù)的原理:
- Vue 2 基于
Object.defineProperty劫持屬性的getter/setter,實(shí)現(xiàn)依賴收集和更新通知。 - Vue 3 基于
Proxy代理整個對象,攔截所有操作,天然支持更多場景的監(jiān)測。
- Vue 2 基于
理解這一機(jī)制有助于避免 “數(shù)據(jù)修改后視圖不更新” 的常見問題,也能更深入地掌握 Vue 響應(yīng)式系統(tǒng)的設(shè)計思想。
到此這篇關(guān)于Vue監(jiān)視數(shù)據(jù)的原理和set()使用方法的文章就介紹到這了,更多相關(guān)Vue監(jiān)視數(shù)據(jù)和set()使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nuxt.js服務(wù)端渲染中axios和proxy代理的配置操作
這篇文章主要介紹了nuxt.js服務(wù)端渲染中axios和proxy代理的配置操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
淺談vue-cli加載不到dev-server.js的解決辦法
本篇文章主要介紹了淺談vue-cli加載不到dev-server.js的解決辦法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
vue常用指令實(shí)現(xiàn)學(xué)生錄入系統(tǒng)的實(shí)戰(zhàn)
本文主要介紹了vue常用指令實(shí)現(xiàn)學(xué)生錄入系統(tǒng)的實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
vue如何隨心所欲調(diào)整el-dialog中body的樣式
這篇文章主要介紹了vue如何隨心所欲調(diào)整el-dialog中body的樣式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
Vue中@click.stop和@click.prevent實(shí)例詳解
當(dāng)我們使用Vue.js開發(fā)前端應(yīng)用時,經(jīng)常會在模版中使用@click指令來響應(yīng)用戶的點(diǎn)擊事件,這篇文章主要給大家介紹了關(guān)于Vue中@click.stop和@click.prevent的相關(guān)資料,需要的朋友可以參考下2024-04-04
Vue如何在CSS中使用data定義的數(shù)據(jù)淺析
這篇文章主要給大家介紹了關(guān)于Vue如何在CSS中使用data定義的數(shù)據(jù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-05-05

