Vue監(jiān)視數(shù)據(jù)的原理和set()的使用方法示例
前言
在 Vue 中,Vue.set()(或 this.$set())是用于解決響應(yīng)式數(shù)據(jù)更新檢測(cè)的重要方法,其底層與 Vue 的數(shù)據(jù)監(jiān)視原理緊密相關(guān)。以下從使用場(chǎng)景和實(shí)現(xiàn)原理兩方面詳細(xì)說明:
一、Vue.set () 的使用場(chǎng)景與用法
1. 為什么需要 Vue.set ()?
Vue 的響應(yīng)式系統(tǒng)通過 Object.defineProperty(Vue 2)或 Proxy(Vue 3)實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽,但存在限制:
- 無法檢測(cè)對(duì)象新增的屬性或刪除的屬性;
- 無法檢測(cè)數(shù)組通過索引修改元素或修改數(shù)組長度的操作。
此時(shí),直接修改數(shù)據(jù)不會(huì)觸發(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)式對(duì)象或數(shù)組(必須是已被 Vue 響應(yīng)式系統(tǒng)劫持的對(duì)象);propertyName/index:新增 / 修改的屬性名(對(duì)象)或索引(數(shù)組);value:對(duì)應(yīng)的值。
3. 典型場(chǎng)景
給對(duì)象新增響應(yīng)式屬性:
data() { return { user: { name: '張三' } } }, methods: { addAge() { // 直接新增屬性,視圖不會(huì)更新 this.user.age = 20; // 無效 // 使用 $set,視圖會(huì)更新 this.$set(this.user, 'age', 20); // 有效 } }修改數(shù)組的指定元素:
data() { return { list: ['蘋果', '香蕉'] } }, methods: { updateItem() { // 直接通過索引修改,視圖不會(huì)更新 this.list[1] = '橙子'; // 無效 // 使用 $set,視圖會(huì)更新 this.$set(this.list, 1, '橙子'); // 有效 } }
二、Vue 監(jiān)視數(shù)據(jù)的原理
Vue 實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式的核心是對(duì)數(shù)據(jù)進(jìn)行劫持,并在數(shù)據(jù)變化時(shí)通知依賴更新視圖。不同 Vue 版本的實(shí)現(xiàn)方式略有差異:
1. Vue 2 的響應(yīng)式原理(Object.defineProperty)
初始化劫持:
當(dāng)組件初始化時(shí),Vue 會(huì)遍歷data中的所有屬性,通過Object.defineProperty為每個(gè)屬性添加getter和setter:getter:當(dāng)屬性被訪問時(shí)觸發(fā),用于收集依賴(記錄哪些視圖 / 計(jì)算屬性依賴該數(shù)據(jù))。setter:當(dāng)屬性被修改時(shí)觸發(fā),用于通知依賴更新(觸發(fā)視圖重新渲染)。
局限性:
- 只能劫持初始化時(shí)已存在的屬性,新增屬性默認(rèn)沒有
getter/setter,因此無法被監(jiān)測(cè)。 - 數(shù)組的
length修改和索引賦值不會(huì)觸發(fā)setter(Vue 對(duì)數(shù)組的 7 個(gè)方法進(jìn)行了重寫,如push、splice等,這些方法會(huì)觸發(fā)更新,但直接修改索引 / 長度不會(huì))。
- 只能劫持初始化時(shí)已存在的屬性,新增屬性默認(rèn)沒有
2. Vue 3 的響應(yīng)式原理(Proxy)
初始化劫持:
Vue 3 使用 ES6 的Proxy對(duì)data對(duì)象進(jìn)行代理,生成一個(gè)代理對(duì)象(Proxy)。Proxy可以攔截對(duì)象的所有操作(包括新增屬性、刪除屬性、索引訪問等),從而解決了 Vue 2 的局限性。優(yōu)勢(shì):
- 能監(jiān)測(cè)新增屬性(
proxy.xxx = value會(huì)被set攔截); - 能監(jiān)測(cè)刪除屬性(
delete proxy.xxx會(huì)被deleteProperty攔截); - 能監(jiān)測(cè)數(shù)組索引修改和長度變化(通過
set攔截)。
- 能監(jiān)測(cè)新增屬性(
三、Vue.set () 的底層實(shí)現(xiàn)邏輯
Vue.set() 的核心作用是手動(dòng)為數(shù)據(jù)添加響應(yīng)式能力,并觸發(fā)更新:
對(duì)于對(duì)象:
- 檢查目標(biāo)對(duì)象是否為響應(yīng)式對(duì)象(是否有
__ob__標(biāo)識(shí),Vue 內(nèi)部用于標(biāo)記響應(yīng)式對(duì)象)。 - 若屬性已存在,則直接修改值并觸發(fā)
setter。 - 若屬性不存在,則通過
Object.defineProperty(Vue 2)或Proxy的set攔截(Vue 3)為新屬性添加響應(yīng)式,并手動(dòng)觸發(fā)依賴更新。
- 檢查目標(biāo)對(duì)象是否為響應(yīng)式對(duì)象(是否有
對(duì)于數(shù)組:
- 調(diào)用數(shù)組的
splice方法(Vue 已重寫該方法,會(huì)觸發(fā)更新),通過splice(index, 1, value)實(shí)現(xiàn)元素修改,從而觸發(fā)視圖更新。
- 調(diào)用數(shù)組的
總結(jié)
- Vue.set () 的作用:解決 Vue 響應(yīng)式系統(tǒng)無法檢測(cè) “對(duì)象新增屬性”“數(shù)組索引修改” 等操作的問題,強(qiáng)制為數(shù)據(jù)添加響應(yīng)式并觸發(fā)視圖更新。
- 監(jiān)視數(shù)據(jù)的原理:
- Vue 2 基于
Object.defineProperty劫持屬性的getter/setter,實(shí)現(xiàn)依賴收集和更新通知。 - Vue 3 基于
Proxy代理整個(gè)對(duì)象,攔截所有操作,天然支持更多場(chǎng)景的監(jiān)測(cè)。
- Vue 2 基于
理解這一機(jī)制有助于避免 “數(shù)據(jù)修改后視圖不更新” 的常見問題,也能更深入地掌握 Vue 響應(yīng)式系統(tǒng)的設(shè)計(jì)思想。
到此這篇關(guān)于Vue監(jiān)視數(shù)據(jù)的原理和set()使用方法的文章就介紹到這了,更多相關(guān)Vue監(jiān)視數(shù)據(jù)和set()使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3封裝AES(CryptoJS)前端加密解密通信代碼實(shí)現(xiàn)
防止數(shù)據(jù)被爬取,前后端傳參接收參數(shù)需要加密處理,使用AES加密,這篇文章主要給大家介紹了關(guān)于vue3封裝AES(CryptoJS)前端加密解密通信代碼實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2023-12-12
關(guān)于ElementUI el-table 鼠標(biāo)滾動(dòng)失靈的問題及解決辦法
這篇文章主要介紹了關(guān)于ElementUI el-table 鼠標(biāo)滾動(dòng)失靈的問題及解決辦法,本文給大家分享問題所在原因及解決方案,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
vue實(shí)現(xiàn)可移動(dòng)的懸浮按鈕
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)可移動(dòng)的懸浮按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
動(dòng)態(tài)實(shí)現(xiàn)element ui的el-table某列數(shù)據(jù)不同樣式的示例
這篇文章主要介紹了動(dòng)態(tài)實(shí)現(xiàn)element ui的el-table某列數(shù)據(jù)不同樣式的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

