vue3響應(yīng)式實(shí)現(xiàn)readonly從零開始教程
前言
前面的章節(jié)我們把 effect
部分大致講完了,這部分我們來講 readonly
以及重構(gòu)一下reactive
。
readonly的實(shí)現(xiàn)
it("happy path", () => { console.warn = vi.fn(); const original = { foo: 1, }; const observed = readonly({ foo: 1, }); expect(original).not.toBe(observed); expect(observed.foo).toBe(1); // set不起作用 observed.foo = 2; expect(observed.foo).toBe(1); // 當(dāng)被set的時(shí)候,發(fā)出一個(gè)警告 expect(console.warn).toBeCalled(); });
其實(shí)與我們之前實(shí)現(xiàn) reactive
十分的類似,區(qū)別只不過是set
的時(shí)候不要觸發(fā)trigger,而是警告。當(dāng)然既然是不會(huì)被改變的,track
也是不必要的。
export function readonly(raw) { return new Proxy(raw, { get(target, key) { const res = Reflect.get(target, key); return res; }, set(target, key, newValue, receiver) { console.warn( `property: ${String(key)} can't be set, beacase ${target} is readonly.` ); return true; }, }); } export function reactive(raw) { return new Proxy(raw, { get(target, key) { const res = Reflect.get(target, key); // 依賴收集 track(target, key); return res; }, set(target, key, value) { const res = Reflect.set(target, key, value); // 觸發(fā)依賴 trigger(target, key); return res; }, }); }
重構(gòu)
可以看到,readonly
和 reactive
實(shí)現(xiàn)其實(shí)很類似,那我們可以重構(gòu)一下,增強(qiáng)后續(xù)的拓展性。
至于我說的類似,指的是 new Proxy(target, handlers)
中的handlers(處理器對(duì)象)中的一些traps(捕獲器)。即get
, set
這些方法。
我們可以通過工廠函數(shù)來創(chuàng)建那些traps函數(shù),來簡(jiǎn)化我們的代碼,提高可維護(hù)性。
另外,我們假定traps可以有工廠可以生產(chǎn)了,即handlers這部分相當(dāng)于被定下來了,new Proxy
這部分也理應(yīng)可以通過工廠函數(shù)創(chuàng)造出來。
我們先抽出一個(gè)公共的文件 baseHandler.ts
// baseHanlder.ts import { track, trigger } from "./effect"; // get的工廠函數(shù) function createGetter(isReadonly = false) { return function get(target, key) { const res = Reflect.get(target, key); if (!isReadonly) { track(target, key); } return res; }; } function createSetter() { return function set(target, key, newValue, receiver) { const res = Reflect.set(target, key, newValue, receiver); trigger(target, key, type, newValue); return res; }; } export const mutableHandler = { get: createGetter(), set: createSetter(), }; export const readonlyHandler = { get: createGetter(), set(target, key, newValue, receiver) { console.warn( `property: ${String(key)} can't be set, beacase ${target} is readonly.` ); return true; };
然后是我們的reactive.ts
// reactive.ts import { mutableHandler, readonlyHandler, } from "./baseHandlers"; // proxy的工廠函數(shù) function createReactiveObject( target, baseHandlers: ProxyHandler<any> ) { return new Proxy(target, baseHandlers); } export function reactive(target) { return createReactiveObject(target, mutableHandler); } export function readonly(target) { return createReactiveObject(target, readonlyHandler); }
結(jié)束
本篇幅比較短小,但是算是為后續(xù)打下了一些基礎(chǔ)吧。因?yàn)楣P者發(fā)現(xiàn)邊學(xué)邊寫總結(jié)文章速度很慢,然后寫完 effect
那幾篇之后就開始直接一路往下學(xué),中途雖然有提交git,但是沒有打tag的習(xí)慣,搞的現(xiàn)在回來來寫文章有點(diǎn)無從下手。
不過最近應(yīng)該快把diff那部分搞定了,到時(shí)候應(yīng)該會(huì)加快速度更新,更多關(guān)于vue3響應(yīng)式readonly的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項(xiàng)目中實(shí)現(xiàn)緩存的最佳方案詳解
這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中實(shí)現(xiàn)緩存的最佳方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07快速了解Vue父子組件傳值以及父調(diào)子方法、子調(diào)父方法
這篇文章主要介紹了Vue父子組件傳值以及父調(diào)子方法、子調(diào)父方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問題的解決方法
這篇文章主要介紹了SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問題,需要的朋友可以參考下2018-01-01vue與vue-i18n結(jié)合實(shí)現(xiàn)后臺(tái)數(shù)據(jù)的多語言切換方法
下面小編就為大家分享一篇vue與vue-i18n結(jié)合實(shí)現(xiàn)后臺(tái)數(shù)據(jù)的多語言切換方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue-cli 3.x配置跨域代理的實(shí)現(xiàn)方法
這篇文章主要介紹了vue-cli 3.x配置跨域代理的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04