一文詳解Vue響應(yīng)式數(shù)據(jù)的原理
在 vue2 的響應(yīng)式中,存在著添加屬性、刪除屬性、以及通過下標(biāo)修改數(shù)組,但頁面不會(huì)自動(dòng)更新的問題。而這些問題在 vue3 中都得以解決。
vue3 采用了 proxy 代理,用于攔截對(duì)象中任意屬性的變化,包括:屬性的讀寫、屬性的添加、屬性的刪除、以及通過下標(biāo)修改數(shù)組,都可以自動(dòng)更新頁面。
proxy 代理:用于在目標(biāo)對(duì)象之前架設(shè)一層攔截,外界對(duì)該對(duì)象的訪問,都必須先通過這層攔截,因此可以對(duì)外界的訪問進(jìn)行過濾和改寫。
另外 vue3 還采用了 reflect 反射,用于對(duì)源對(duì)象的屬性進(jìn)行操作。
reflect 反射:是一個(gè) JS 的內(nèi)置對(duì)象,它提供了一系列的方法,這些方法和對(duì)象中的功能相對(duì)應(yīng)。經(jīng)常配合 proxy 使用。proxy 用于攔截,reflect 用于操作。
Proxy 代理的使用【代理對(duì)象】:
// 假設(shè)這個(gè)是我們創(chuàng)建的 reactive 數(shù)據(jù) const data = { name: "張三", age: 21 }; // 創(chuàng)建 proxy 代理 data 對(duì)象,添加到 vue 的實(shí)例對(duì)象中 // 語法:const vm = new Proxy(要代理的數(shù)據(jù), 配置對(duì)象) const vm = new Proxy(data, { // 當(dāng)有人讀取 vm 的某個(gè)屬性時(shí)調(diào)用 get(target, propName) { // target 就是被代理的這個(gè)對(duì)象,propName 就是當(dāng)前操作的屬性 console.log(`有人讀取了vm身上的${propName}屬性`); return target[propName]; // 返回代理對(duì)象中的這個(gè)屬性 }, // 當(dāng)有人修改 vm 的某個(gè)屬性時(shí),或給 vm 添加某個(gè)屬性時(shí)調(diào)用 set(target, propName, value) { // value 就是修改的值 console.log(`有人修改了vm身上的${propName}屬性,我要去更新頁面了!`); return (target[index] = value); // 修改或添加這個(gè)屬性 }, // 當(dāng)有人刪除 vm 的某個(gè)屬性時(shí)調(diào)用 deleteProperty(target, propName) { console.log(`有人刪除了vm身上的${propName}屬性,我要去更新頁面了!`); return delete target[propName]; // 刪除代理對(duì)象中的這個(gè)屬性 }, });
注:proxy 不僅能檢測(cè)到讀取屬性和修改屬性,還能檢測(cè)到添加屬性和刪除屬性。所以在 vue3 中添加或刪除一個(gè)對(duì)象中的屬性時(shí),頁面也會(huì)自動(dòng)更新。
注:讀取時(shí)觸發(fā) get 函數(shù)、修改或添加時(shí)觸發(fā) set 函數(shù)、刪除時(shí)觸發(fā) deleteProperty 函數(shù)。
Proxy 代理的使用【代理數(shù)組】:
// 假設(shè)這個(gè)是我們創(chuàng)建的 reactive 數(shù)據(jù) const arr = ["張三", "李四", "王五"]; // 創(chuàng)建 proxy 代理 arr 數(shù)組,添加到 vue 的實(shí)例對(duì)象中 // 語法:const app = new Proxy(要代理的數(shù)據(jù), 配置對(duì)象) const app = new Proxy(arr, { // 當(dāng)有人讀取 app 的某個(gè)值時(shí)調(diào)用 get(target, index) { // target 就是被代理的這個(gè)數(shù)組,index 就是當(dāng)前操作的屬性或下標(biāo) console.log(`有人讀取了app身上下標(biāo)${index}的值`); return target[index]; // 返回代理數(shù)組中的這個(gè)值 }, // 當(dāng)有人修改 app 的某個(gè)值時(shí),或給 app 添加一個(gè)值時(shí)調(diào)用 set(target, index, value) { // value 就是修改的值 console.log(`有人修改了app身上下標(biāo)${index}的值,我要去更新頁面了!`); return (target[index] = value); // 修改或添加代理數(shù)組中的這個(gè)值 }, // 當(dāng)有人刪除 app 的某個(gè)值時(shí)調(diào)用 deleteProperty(target, index) { console.log(`有人刪除了app身上下標(biāo)${index}的值,我要去更新頁面了!`); return delete target[index]; // 刪除代理數(shù)組中的這個(gè)值 }, });
注:proxy 支持通過下標(biāo)操作數(shù)組,例如查看數(shù)據(jù)、修改數(shù)據(jù)、增加數(shù)據(jù)。所以在 vue3 中通過下標(biāo)修改數(shù)組時(shí),頁面也會(huì)自動(dòng)更新。
注:在使用 push 等方法的時(shí)候,length 屬性也會(huì)發(fā)生變化。所以 vue3 分別判斷了 push、pop、unshift、shift 等方法,用于區(qū)分?jǐn)r截的各種情況。
Proxy 代理的使用【深層數(shù)據(jù)的問題】
const data = { name: "張三", age: 20, arr: ["a", "b", "c"], obj: { q: 1, w: 2 }, }; const app = new Proxy(data, { get(target, propName) { console.log(`有人讀取了app身上的${propName}屬性`); return target[propName]; }, set(target, propName, value) { console.log(`有人修改了app身上的${propName}屬性,我要去更新頁面了!`); return (target[propName] = value); }, deleteProperty(target, propName) { console.log(`有人刪除了app身上的${propName}屬性,我要去更新頁面了!`); return delete target[propName]; }, });
注:proxy 代理深層數(shù)據(jù)的時(shí)候,只會(huì)觸發(fā) get 函數(shù),并不會(huì)觸發(fā) set 函數(shù)
注:proxy 只會(huì)攔截第一層數(shù)據(jù),所以 vue3 對(duì)深層數(shù)據(jù)進(jìn)行了循環(huán)遍歷,重新利用 proxy 代理了深層數(shù)據(jù)。
到此這篇關(guān)于一文詳解Vue響應(yīng)式數(shù)據(jù)的原理的文章就介紹到這了,更多相關(guān)Vue響應(yīng)式數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
el-select單選時(shí)選擇后輸入框的is-focus狀態(tài)并沒有取消問題解決
這篇文章主要給大家介紹了關(guān)于el-select單選時(shí)選擇后輸入框的is-focus狀態(tài)并沒有取消問題的解決過程,文中通過圖文以及代碼示例將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01

springboot+vue實(shí)現(xiàn)文件上傳下載

vue項(xiàng)目實(shí)現(xiàn)便捷接入百度地圖API

vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類似輪播圖效果)

vue3中vite.config.js相關(guān)常用配置超詳細(xì)講解

淺析Proxy如何實(shí)現(xiàn)Vue響應(yīng)式