电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

如何在Vue中使localStorage具有響應式(思想實驗)

瀏覽:139日期:2023-01-07 18:45:35

響應式是Vue.js的最大特色之一。如果你不知道幕后情況,它也是最神秘的地方之一。例如,為什么它不能用于對象和數組,而不能用于諸如 localStorage 之類的其他東西?

如何在Vue中使localStorage具有響應式(思想實驗)

讓我們回答這個問題,在解決這個問題時,讓Vue響應式與 localStorage 一起使用。

如果運行以下代碼,則會看到計數器顯示為靜態值,并且不會像我們期望的那樣發生變化,這是因為setInterval在 localStorage 中更改了該值。

new Vue({ el: '#counter', data: () => ({ counter: localStorage.getItem('counter') }), computed: { even() { return this.counter % 2 == 0; } }, template: `<div> <div>Counter: {{ counter }}</div> <div>Counter is {{ even ? ’even’ : ’odd’ }}</div> </div>` });

// some-other-file.js setInterval(() => { const counter = localStorage.getItem('counter'); localStorage.setItem('counter', +counter + 1); }, 1000);

盡管Vue.js實例中的 counter 屬性是響應式的,但它不會因為我們更改了它在 localStorage 中的來源而更改。

有多種解決方案,最好的也許是使用Vuex,并保持存儲值與 localStorage 同步。但如果我們需要像本例中那樣簡單的東西呢?我們要深入了解一下Vue.js的響應式系統是如何工作的。

Vue 中的響應式

當Vue初始化組件實例時,它將觀察data選項。這意味著它將遍歷數據中的所有屬性,并使用 Object.defineProperty 將它們轉換為getter/setter。通過為每個屬性設置自定義設置器,Vue可以知道屬性何時發生更改,并且可以通知需要對更改做出反應的依賴者。它如何知道哪些依賴者依賴于一個屬性?通過接入getters,它可以在計算的屬性、觀察者函數或渲染函數訪問數據屬性時進行注冊。

// core/instance/state.js function initData () { // ... observe(data) }

// core/observer/index.js export function observe (value) { // ... new Observer(value) // ... } export class Observer { // ... constructor (value) { // ... this.walk(value) } walk (obj) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } } export function defineReactive (obj, key, ...) { const dep = new Dep() // ... Object.defineProperty(obj, key, { // ... get() { // ... dep.depend() // ... }, set(newVal) { // ... dep.notify() } }) }

所以,為什么 localStorage 不響應?因為它不是具有屬性的對象。

但是等一下,我們也不能用數組定義getter和setter,但Vue中的數組仍然是反應式的。這是因為數組在Vue中是一種特殊情況。為了擁有響應式的數組,Vue在后臺重寫了數組方法,并與Vue的響應式系統進行了修補。

我們可以對 localStorage 做類似的事情嗎?

覆蓋localStorage函數

首先嘗試通過覆蓋localStorage方法來修復最初的示例,以跟蹤哪些組件實例請求了localStorage項目。

// LocalStorage項目鍵與依賴它的Vue實例列表之間的映射。 const storeItemSubscribers = {}; const getItem = window.localStorage.getItem; localStorage.getItem = (key, target) => { console.info('Getting', key); // 收集依賴的Vue實例 if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; if (target) storeItemSubscribers[key].push(target); // 調用原始函數 return getItem.call(localStorage, key); }; const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) => { console.info('Setting', key, value); // 更新相關Vue實例中的值 if (storeItemSubscribers[key]) { storeItemSubscribers[key].forEach((dep) => { if (dep.hasOwnProperty(key)) dep[key] = value; }); } // 調用原始函數 setItem.call(localStorage, key, value); };

new Vue({ el: '#counter', data: function() { return { counter: localStorage.getItem('counter', this) // 我們現在需要傳遞“this” } }, computed: { even() { return this.counter % 2 == 0; } }, template: `<div> <div>Counter: {{ counter }}</div> <div>Counter is {{ even ? ’even’ : ’odd’ }}</div> </div>` });

setInterval(() => { const counter = localStorage.getItem('counter'); localStorage.setItem('counter', +counter + 1); }, 1000);

在這個例子中,我們重新定義了 getItem 和 setItem,以便收集和通知依賴 localStorage 項目的組件。在新的 getItem 中,我們注意到哪個組件請求了哪個項目,在 setItems 中,我們聯系所有請求該項目的組件,并重寫它們的數據屬性。

為了使上面的代碼工作,我們必須向 getItem 傳遞一個對組件實例的引用,這就改變了它的函數簽名。我們也不能再使用箭頭函數了,因為否則我們就不會有正確的 this 值。

如果我們想做得更好,就必須更深入地挖掘。例如,我們如何在不顯式傳遞依賴者的情況下跟蹤它們?

如何在Vue中使localStorage具有響應式(思想實驗)

Vue如何收集依賴關系

為了獲得啟發,我們可以回到Vue的響應式系統。我們之前曾看到,訪問數據屬性時,數據屬性的 getter 將使調用者訂閱該屬性的進一步更改。但是它怎么知道是誰做的調用呢?當我們得到一個數據屬性時,它的 getter 函數沒有任何關于調用者是誰的輸入。Getter函數沒有輸入,它怎么知道誰要注冊為依賴者呢?

每個數據屬性維護一個需要在Dep類中進行響應的依賴項列表。如果我們在此類中進行更深入的研究,可以看到只要在注冊依賴項時就已經在靜態目標變量中定義了依賴項。這個目標是由一個非常神秘的Watche類確定的。實際上,當數據屬性更改時,將實際通知這些觀察程序,并且它們將啟動組件的重新渲染或計算屬性的重新計算。

但是,他們又是誰?

當Vue使 data 選項可觀察時,它還會為每個計算出的屬性函數以及所有watch函數(不應與Watcher類混為一談)以及每個組件實例的render函數創建watcher。觀察者就像這些函數的伴侶。他們主要做兩件事:

當它們被創建時,它們會評估函數。這將觸發依賴關系的集合。 當他們被通知他們所依賴的一個值發生變化時,他們會重新運行他們的函數。這將最終重新計算一個計算出的屬性或重新渲染整個組件。

在觀察者調用其負責的函數之前,有一個重要的步驟發生了:他們將自己設置為Dep類中靜態變量的目標。這樣可以確保在訪問響應式數據屬性時將它們注冊為從屬。

追蹤誰調用了localStorage

我們無法完全做到這一點,因為我們無法使用Vue的內部機制。但是,我們可以使用Vue的想法,即觀察者可以在調用其負責的函數之前,將目標設置為靜態屬性。我們能否在調用 localStorage 之前設置對組件實例的引用?

如果我們假設在設置 data 選項時調用了 localStorage,則可以將其插入 beforeCreate 和 created 中。這兩個掛鉤在初始化data選項之前和之后都會被觸發,因此我們可以設置一個目標變量,然后清除該變量,并引用當前組件實例(我們可以在生命周期掛鉤中訪問該實例)。然后,在我們的自定義獲取器中,我們可以將該目標注冊為依賴項。

我們要做的最后一點是使這些生命周期掛鉤成為我們所有組件的一部分,我們可以通過整個項目的全局混合來做到這一點。

// LocalStorage項目鍵與依賴它的Vue實例列表之間的映射 const storeItemSubscribers = {}; // 當前正在初始化的Vue實例 let target = undefined; const getItem = window.localStorage.getItem; localStorage.getItem = (key) => { console.info('Getting', key); // 收集依賴的Vue實例 if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; if (target) storeItemSubscribers[key].push(target); // 調用原始函數 return getItem.call(localStorage, key); }; const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) => { console.info('Setting', key, value); // 更新相關Vue實例中的值 if (storeItemSubscribers[key]) { storeItemSubscribers[key].forEach((dep) => { if (dep.hasOwnProperty(key)) dep[key] = value; }); } // 調用原始函數 setItem.call(localStorage, key, value); }; Vue.mixin({ beforeCreate() { console.log('beforeCreate', this._uid); target = this; }, created() { console.log('created', this._uid); target = undefined; } });

現在,當我們運行第一個示例時,我們將獲得一個計數器,該計數器每秒增加一個數字。

new Vue({ el: '#counter', data: () => ({ counter: localStorage.getItem('counter') }), computed: { even() { return this.counter % 2 == 0; } }, template: `<div class='component'> <div>Counter: {{ counter }}</div> <div>Counter is {{ even ? ’even’ : ’odd’ }}</div> </div>` });

setInterval(() => { const counter = localStorage.getItem('counter'); localStorage.setItem('counter', +counter + 1); }, 1000);

我們的思想實驗結束

當我們解決了最初的問題時,請記住這主要是一個思想實驗。它缺少一些功能,例如處理已刪除的項目和未安裝的組件實例。它還具有一些限制,例如組件實例的屬性名稱需要與存儲在 localStorage 中的項目相同的名稱。就是說,主要目標是更好地了解Vue響應式在幕后的工作方式并充分利用這一點,因此,我希望你能從所有這些事情中受益。

到此這篇關于如何在Vue中使localStorage具有響應式的文章就介紹到這了,更多相關Vue localStorage響應式內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Vue
相關文章:
主站蜘蛛池模板: 3dmax渲染-效果图渲染-影视动画渲染-北京快渲科技有限公司 | 南京PVC快速门厂家南京快速卷帘门_南京pvc快速门_世界500强企业国内供应商_南京美高门业 | 餐饮加盟网_特色餐饮加盟店_餐饮连锁店加盟 | 安驭邦官网-双向万能直角铣头,加工中心侧铣头,角度头[厂家直销] 闸阀_截止阀_止回阀「生产厂家」-上海卡比阀门有限公司 | 工业硝酸钠,硝酸钠厂家-淄博「文海工贸」 | uv固化机-丝印uv机-工业烤箱-五金蚀刻机-分拣输送机 - 保定市丰辉机械设备制造有限公司 | 999范文网_优质范文下载写作帮手| 东莞市踏板石餐饮管理有限公司_正宗桂林米粉_正宗桂林米粉加盟_桂林米粉加盟费-东莞市棒子桂林米粉 | 色谱柱-淋洗液罐-巴罗克试剂槽-巴氏吸管-5ml样品瓶-SBS液氮冻存管-上海希言科学仪器有限公司 | 换链神器官网-友情链接交换、购买交易于一体的站长平台 | 美侍宠物-专注宠物狗及宠物猫训练|喂养|医疗|繁育|品种|价格 | 无硅导热垫片-碳纤维导热垫片-导热相变材料厂家-东莞市盛元新材料科技有限公司 | 上海诺狮景观规划设计有限公司 | 宁夏档案密集柜,智能密集柜,电动手摇密集柜-盛隆柜业宁夏档案密集柜厂家 | 工业rfid读写器_RFID工业读写器_工业rfid设备厂商-ANDEAWELL | 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 - 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 | 三佳互联一站式网站建设服务|网站开发|网站设计|网站搭建服务商 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 等离子表面处理机-等离子表面活化机-真空等离子清洗机-深圳市东信高科自动化设备有限公司 | 河南15年专业网站建设制作设计,做网站就找郑州启凡网络公司 | 楼承板-钢筋楼承板-闭口楼承板-无锡优贝斯楼承板厂 | IHDW_TOSOKU_NEMICON_EHDW系列电子手轮,HC1系列电子手轮-上海莆林电子设备有限公司 | 集装袋吨袋生产厂家-噸袋廠傢-塑料编织袋-纸塑复合袋-二手吨袋-太空袋-曹县建烨包装 | 东莞精密模具加工,精密连接器模具零件,自動機零件,冶工具加工-益久精密 | 耐磨陶瓷管道_除渣器厂家-淄博浩瀚陶瓷科技有限公司 | 3D全息投影_地面互动投影_360度立体投影_水幕灯光秀 | 广东银虎 蜂窝块状沸石分子筛-吸附脱硫分子筛-萍乡市捷龙环保科技有限公司 | 飞扬动力官网-广告公司管理软件,广告公司管理系统,喷绘写真条幅制作管理软件,广告公司ERP系统 | 团建-拓展-拓展培训-拓展训练-户外拓展训练基地[无锡劲途] | PU树脂_水性聚氨酯树脂_聚氨酯固化剂_聚氨酯树脂厂家_宝景化工 | 称重传感器,测力传感器,拉压力传感器,压力变送器,扭矩传感器,南京凯基特电气有限公司 | 金库门,金库房,金库门厂家,金库门价格-河北特旺柜业有限公司 | 理化生实验室设备,吊装实验室设备,顶装实验室设备,实验室成套设备厂家,校园功能室设备,智慧书法教室方案 - 东莞市惠森教学设备有限公司 | 折弯机-刨槽机-数控折弯机-数控刨槽机-数控折弯机厂家-深圳豐科机械有限公司 | 棉服定制/厂家/公司_棉袄订做/价格/费用-北京圣达信棉服 | 注塑_注塑加工_注塑模具_塑胶模具_注塑加工厂家_深圳环科 | 天津货架厂_穿梭车货架_重型仓储货架_阁楼货架定制-天津钢力仓储货架生产厂家_天津钢力智能仓储装备 | 板框压滤机-隔膜压滤机-厢式压滤机生产厂家-禹州市君工机械设备有限公司 | 环氧乙烷灭菌器_压力蒸汽灭菌器_低温等离子过氧化氢灭菌器 _低温蒸汽甲醛灭菌器_清洗工作站_医用干燥柜_灭菌耗材-环氧乙烷灭菌器_脉动真空压力蒸汽灭菌器_低温等离子灭菌设备_河南省三强医疗器械有限责任公司 | 北京翻译公司_同传翻译_字幕翻译_合同翻译_英语陪同翻译_影视翻译_翻译盖章-译铭信息 | 展厅设计公司,展厅公司,展厅设计,展厅施工,展厅装修,企业展厅,展馆设计公司-深圳广州展厅设计公司 | 匀胶机旋涂仪-声扫显微镜-工业水浸超声-安赛斯(北京)科技有限公司 | 登车桥动力单元-非标液压泵站-非标液压系统-深圳市三好科技有限公司 |