欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何在Vue中使localStorage具有響應(yīng)式(思想實(shí)驗(yàn))

 更新時(shí)間:2020年07月14日 15:17:35   作者:做工程師不做碼農(nóng)  
這篇文章主要介紹了如何在Vue中使localStorage具有響應(yīng)式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

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

讓我們回答這個(gè)問題,在解決這個(gè)問題時(shí),讓Vue響應(yīng)式與 localStorage 一起使用。

如果運(yùn)行以下代碼,則會(huì)看到計(jì)數(shù)器顯示為靜態(tài)值,并且不會(huì)像我們期望的那樣發(fā)生變化,這是因?yàn)閟etInterval在 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實(shí)例中的 counter 屬性是響應(yīng)式的,但它不會(huì)因?yàn)槲覀兏牧怂?localStorage 中的來源而更改。

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

Vue 中的響應(yīng)式

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

// 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 不響應(yīng)?因?yàn)樗皇蔷哂袑傩缘膶?duì)象。

但是等一下,我們也不能用數(shù)組定義getter和setter,但Vue中的數(shù)組仍然是反應(yīng)式的。這是因?yàn)閿?shù)組在Vue中是一種特殊情況。為了擁有響應(yīng)式的數(shù)組,Vue在后臺(tái)重寫了數(shù)組方法,并與Vue的響應(yīng)式系統(tǒng)進(jìn)行了修補(bǔ)。

我們可以對(duì) localStorage 做類似的事情嗎?

覆蓋localStorage函數(shù)

首先嘗試通過覆蓋localStorage方法來修復(fù)最初的示例,以跟蹤哪些組件實(shí)例請(qǐng)求了localStorage項(xiàng)目。

// LocalStorage項(xiàng)目鍵與依賴它的Vue實(shí)例列表之間的映射。 
const storeItemSubscribers = {}; 
 
const getItem = window.localStorage.getItem; 
localStorage.getItem = (key, target) => { 
 console.info("Getting", key); 
 
 // 收集依賴的Vue實(shí)例 
 if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; 
 if (target) storeItemSubscribers[key].push(target); 
 
 // 調(diào)用原始函數(shù) 
 return getItem.call(localStorage, key); 
}; 
 
const setItem = window.localStorage.setItem; 
localStorage.setItem = (key, value) => { 
 console.info("Setting", key, value); 
 
 // 更新相關(guān)Vue實(shí)例中的值 
 if (storeItemSubscribers[key]) { 
  storeItemSubscribers[key].forEach((dep) => { 
   if (dep.hasOwnProperty(key)) dep[key] = value; 
  }); 
 } 
 
 // 調(diào)用原始函數(shù) 
 setItem.call(localStorage, key, value); 
}; 
new Vue({ 
 el: "#counter", 
 data: function() { 
  return { 
   counter: localStorage.getItem("counter", this) // 我們現(xiàn)在需要傳遞“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); 

在這個(gè)例子中,我們重新定義了 getItem 和 setItem,以便收集和通知依賴 localStorage 項(xiàng)目的組件。在新的 getItem 中,我們注意到哪個(gè)組件請(qǐng)求了哪個(gè)項(xiàng)目,在 setItems 中,我們聯(lián)系所有請(qǐng)求該項(xiàng)目的組件,并重寫它們的數(shù)據(jù)屬性。

為了使上面的代碼工作,我們必須向 getItem 傳遞一個(gè)對(duì)組件實(shí)例的引用,這就改變了它的函數(shù)簽名。我們也不能再使用箭頭函數(shù)了,因?yàn)榉駝t我們就不會(huì)有正確的 this 值。

如果我們想做得更好,就必須更深入地挖掘。例如,我們?nèi)绾卧诓伙@式傳遞依賴者的情況下跟蹤它們?

Vue如何收集依賴關(guān)系

為了獲得啟發(fā),我們可以回到Vue的響應(yīng)式系統(tǒng)。我們之前曾看到,訪問數(shù)據(jù)屬性時(shí),數(shù)據(jù)屬性的 getter 將使調(diào)用者訂閱該屬性的進(jìn)一步更改。但是它怎么知道是誰做的調(diào)用呢?當(dāng)我們得到一個(gè)數(shù)據(jù)屬性時(shí),它的 getter 函數(shù)沒有任何關(guān)于調(diào)用者是誰的輸入。Getter函數(shù)沒有輸入,它怎么知道誰要注冊(cè)為依賴者呢?

每個(gè)數(shù)據(jù)屬性維護(hù)一個(gè)需要在Dep類中進(jìn)行響應(yīng)的依賴項(xiàng)列表。如果我們?cè)诖祟愔羞M(jìn)行更深入的研究,可以看到只要在注冊(cè)依賴項(xiàng)時(shí)就已經(jīng)在靜態(tài)目標(biāo)變量中定義了依賴項(xiàng)。這個(gè)目標(biāo)是由一個(gè)非常神秘的Watche類確定的。實(shí)際上,當(dāng)數(shù)據(jù)屬性更改時(shí),將實(shí)際通知這些觀察程序,并且它們將啟動(dòng)組件的重新渲染或計(jì)算屬性的重新計(jì)算。

但是,他們又是誰?

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

  • 當(dāng)它們被創(chuàng)建時(shí),它們會(huì)評(píng)估函數(shù)。這將觸發(fā)依賴關(guān)系的集合。
  • 當(dāng)他們被通知他們所依賴的一個(gè)值發(fā)生變化時(shí),他們會(huì)重新運(yùn)行他們的函數(shù)。這將最終重新計(jì)算一個(gè)計(jì)算出的屬性或重新渲染整個(gè)組件。

在觀察者調(diào)用其負(fù)責(zé)的函數(shù)之前,有一個(gè)重要的步驟發(fā)生了:他們將自己設(shè)置為Dep類中靜態(tài)變量的目標(biāo)。這樣可以確保在訪問響應(yīng)式數(shù)據(jù)屬性時(shí)將它們注冊(cè)為從屬。

追蹤誰調(diào)用了localStorage

我們無法完全做到這一點(diǎn),因?yàn)槲覀儫o法使用Vue的內(nèi)部機(jī)制。但是,我們可以使用Vue的想法,即觀察者可以在調(diào)用其負(fù)責(zé)的函數(shù)之前,將目標(biāo)設(shè)置為靜態(tài)屬性。我們能否在調(diào)用 localStorage 之前設(shè)置對(duì)組件實(shí)例的引用?

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

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

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

現(xiàn)在,當(dāng)我們運(yùn)行第一個(gè)示例時(shí),我們將獲得一個(gè)計(jì)數(shù)器,該計(jì)數(shù)器每秒增加一個(gè)數(shù)字。

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); 

我們的思想實(shí)驗(yàn)結(jié)束

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

到此這篇關(guān)于如何在Vue中使localStorage具有響應(yīng)式的文章就介紹到這了,更多相關(guān)Vue localStorage響應(yīng)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue+Echarts實(shí)現(xiàn)繪制動(dòng)態(tài)折線圖

    Vue+Echarts實(shí)現(xiàn)繪制動(dòng)態(tài)折線圖

    這篇文章主要為大家詳細(xì)介紹了如何利用Vue和Echarts實(shí)現(xiàn)繪制動(dòng)態(tài)折線圖,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • vue自動(dòng)添加瀏覽器兼容前后綴操作

    vue自動(dòng)添加瀏覽器兼容前后綴操作

    這篇文章主要介紹了vue自動(dòng)添加瀏覽器兼容前后綴操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 深入探索Vue中樣式綁定的七種實(shí)現(xiàn)方法

    深入探索Vue中樣式綁定的七種實(shí)現(xiàn)方法

    在?Vue.js?開發(fā)中,合理地控制元素的樣式對(duì)于構(gòu)建高質(zhì)量的用戶界面至關(guān)重要,Vue?提供了靈活的方式來綁定樣式,這篇文章將探索?Vue?中設(shè)置樣式的七種做法,并結(jié)合代碼,逐步說明每種方法的實(shí)現(xiàn),需要的朋友可以參考下
    2024-03-03
  • Vue使用.sync 實(shí)現(xiàn)父子組件的雙向綁定數(shù)據(jù)問題

    Vue使用.sync 實(shí)現(xiàn)父子組件的雙向綁定數(shù)據(jù)問題

    這篇文章主要介紹了Vue使用.sync 實(shí)現(xiàn)父子組件的雙向綁定數(shù)據(jù),需要的朋友可以參考下
    2019-04-04
  • Vue2和Vue3中如何使用WebSocker封裝詳解

    Vue2和Vue3中如何使用WebSocker封裝詳解

    如果項(xiàng)目中多個(gè)組件都使用到WebSocket請(qǐng)求,那么我們需要對(duì)WebSocket進(jìn)行封裝,方便我們使用,下面這篇文章主要給大家介紹了關(guān)于Vue2和Vue3中如何使用WebSocker封裝的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • vue.js管理后臺(tái)table組件封裝的方法

    vue.js管理后臺(tái)table組件封裝的方法

    table作為數(shù)據(jù)展示組件,在日常開發(fā)中經(jīng)常被用到,這篇文章主要給大家介紹了關(guān)于vue.js管理后臺(tái)table組件封裝的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • Vue使用echarts繪制柱狀圖和折線圖

    Vue使用echarts繪制柱狀圖和折線圖

    這篇文章主要為大家學(xué)習(xí)介紹了Vue如何使用echarts繪制柱狀圖和折線圖,文中有詳細(xì)的示例代碼,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-08-08
  • Vue中使用sass實(shí)現(xiàn)換膚功能

    Vue中使用sass實(shí)現(xiàn)換膚功能

    這篇文章主要介紹了Vue中使用sass實(shí)現(xiàn)換膚功能,實(shí)現(xiàn)此功能用到了三個(gè)主要文件(base.scss、mixin.scss、varibale.scss),需要的朋友可以參考下
    2018-09-09
  • vue如何利用store實(shí)現(xiàn)兩個(gè)平行組件間的傳值

    vue如何利用store實(shí)現(xiàn)兩個(gè)平行組件間的傳值

    這篇文章主要介紹了vue如何利用store實(shí)現(xiàn)兩個(gè)平行組件間的傳值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue?echarts實(shí)現(xiàn)航班選座案例分析

    vue?echarts實(shí)現(xiàn)航班選座案例分析

    這篇文章主要介紹了vue?echarts實(shí)現(xiàn)航班選座案例分析,代碼是使用echarts來實(shí)現(xiàn)的,主要用到的是svg和自定義地圖的相關(guān)知識(shí),需要的朋友可以參考下
    2022-05-05

最新評(píng)論