一文帶你深入理解Vue3響應(yīng)式原理
響應(yīng)式原理
Vue2 使用的是 Object.defineProperty Vue3 使用的是 Proxy
2.0的不足
對(duì)象只能劫持 設(shè)置好的數(shù)據(jù),新增的數(shù)據(jù)需要Vue.Set(xxx) 數(shù)組只能操作七種方法,修改某一項(xiàng)值無法劫持。
reactive和effect的實(shí)現(xiàn)
export const reactive = <T extends object>(target:T) => { return new Proxy(target,{ get (target,key,receiver) { const res = Reflect.get(target,key,receiver) as object return res }, set (target,key,value,receiver) { const res = Reflect.set(target,key,value,receiver) return res } }) }
Vue3 的響應(yīng)式原理依賴了 Proxy 這個(gè)核心 API,通過 Proxy 可以劫持對(duì)象的某些操作。
effect track trigger
實(shí)現(xiàn)effect 副作用函數(shù)
let activeEffect; export const effect = (fn:Function) => { const _effect = function () { activeEffect = _effect; fn() } _effect() }
使用一個(gè)全局變量 active 收集當(dāng)前副作用函數(shù),并且初始化的時(shí)候調(diào)用一下
實(shí)現(xiàn)track
const targetMap = new WeakMap() export const track = (target,key) =>{ let depsMap = targetMap.get(target) if(!depsMap){ depsMap = new Map() targetMap.set(target,depsMap) } let deps = depsMap.get(key) if(!deps){ deps = new Set() depsMap.set(key,deps) } deps.add(activeEffect) }
執(zhí)行完成成后我們得到一個(gè)如下的數(shù)據(jù)結(jié)構(gòu)
實(shí)現(xiàn)trigger
export const trigger = (target,key) => { const depsMap = targetMap.get(target) const deps = depsMap.get(key) deps.forEach(effect=>effect()) }
當(dāng)我們進(jìn)行賦值的時(shí)候會(huì)調(diào)用 set 然后 觸發(fā)收集的副作用函數(shù)
import {track,trigger} from './effect' export const reactive = <T extends object>(target:T) => { return new Proxy(target,{ get (target,key,receiver) { const res = Reflect.get(target,key,receiver) as object track(target,key) return res }, set (target,key,value,receiver) { const res = Reflect.set(target,key,value,receiver) trigger(target,key) return res } }) }
給 reactive 添加這兩個(gè)方法
測(cè)試代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> </div> <script type="module"> import { reactive } from './reactive.js' import { effect } from './effect.js' const user = reactive({ name: "小滿", age: 18 }) effect(() => { document.querySelector('#app').innerText = `${user.name} - ${user.age}` }) setTimeout(()=>{ user.name = '大滿很厲害' setTimeout(()=>{ user.age = '23' },1000) },2000) </script> </body> </html>
遞歸實(shí)現(xiàn)reactive
import { track, trigger } from './effect' const isObject = (target) => target != null && typeof target == 'object' export const reactive = <T extends object>(target: T) => { return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver) as object track(target, key) if (isObject(res)) { return reactive(res) } return res }, set(target, key, value, receiver) { const res = Reflect.set(target, key, value, receiver) trigger(target, key) return res } }) }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> </div> <script type="module"> import { reactive } from './reactive.js' import { effect } from './effect.js' const user = reactive({ name: "小滿", age: 18, foo:{ bar:{ sss:123 } } }) effect(() => { document.querySelector('#app').innerText = `${user.name} - ${user.age}-${user.foo.bar.sss}` }) setTimeout(()=>{ user.name = '大滿很厲害' setTimeout(()=>{ user.age = '23' setTimeout(()=>{ user.foo.bar.sss = 66666666 },1000) },1000) },2000) </script> </body> </html>
總結(jié)
到此這篇關(guān)于Vue3響應(yīng)式原理的文章就介紹到這了,更多相關(guān)Vue3響應(yīng)式原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Vue實(shí)現(xiàn)封裝一個(gè)虛擬列表組件
正常情況下,我們對(duì)于數(shù)據(jù)都會(huì)分頁加載,最近項(xiàng)目中確實(shí)遇到了不能分頁的場(chǎng)景,如果不分頁,頁面渲染幾千條數(shù)據(jù)就會(huì)感知到卡頓,使用虛擬列表就勢(shì)在必行了。本文主要介紹了如何基于Vue實(shí)現(xiàn)封裝一個(gè)虛擬列表組件,感興趣的可以了解一下2023-03-03vue結(jié)合leaflet實(shí)現(xiàn)地圖放大鏡
放大鏡在很多地方都可以使用的到,本文主要介紹了vue結(jié)合leaflet實(shí)現(xiàn)地圖放大鏡,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06詳解vue-cli開發(fā)環(huán)境跨域問題解決方案
本篇文章主要介紹了vue-cli開發(fā)環(huán)境跨域問題解決方案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-06-06Vue首頁界面加載優(yōu)化實(shí)現(xiàn)方法詳解
如果你也遇到在 vue 應(yīng)用中,首頁加載資源過多,導(dǎo)致加載緩慢的問題,下面的方法也許能幫到你,主要的處理思想是:讓首頁多余的資源能在需要它的時(shí)候再加載2022-09-09vue不用import直接調(diào)用實(shí)現(xiàn)接口api文件封裝
這篇文章主要為大家介紹了vue不用import直接調(diào)用實(shí)現(xiàn)接口api文件封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06VUE路由動(dòng)態(tài)加載實(shí)例代碼講解
在本文里小編給大家整理了關(guān)于VUE路由動(dòng)態(tài)加載實(shí)例代碼以及相關(guān)知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。2019-08-08