談談StorageEvent

紛紛紅紫已成塵,布穀聲中夏令新。夾路桑麻行不盡,始知身是太平人。 ——宋.陸游 《初夏絕句》javascript

咱們在開發多Tab應用時候,經常會遇到多個Tab狀態同步的問題。css

想象以下場景:用戶主界面,顯示用戶購物車內待結算的商品總數。此時,用戶可能打開多個Tab。當用戶添加新商品到購物車的時候,須要更新購物車的數量。html

此時,當前頁面須要向服務器發起請求,在獲得添加成功響應的時候,能夠更新用戶界面。爲了兼顧體驗和可靠性,若是確信添加成功機率比較高的時候,也能夠先更新界面,當多數返回錯誤的時候,能夠給用戶界面作狀態回滾。爲了下次展現方便,咱們還會把這個數據寫到LocalStorage裏面。用戶再次打開時候,能夠優先從localStorage中取值。前端

當前頁面解決了,那麼若是同時打開多個Tab該如何解決呢?這裏使用StorageEvent多是一種代價較小的解決方案。java

StorageEvent是什麼呢?編程

  1. 是一種Event,能夠經過標準的Event監聽器操做。
  2. 當storage變化時候,事件會被派發到全部同域下的其餘頁面。
  3. 觸發變化的當前頁面,沒有事件派發。

這裏有一個簡單的示例能夠展現這個API的用法。服務器

const STORAGE_KEY = "cartlist"

const getStorage = () => {
	try {
		let rets = window.localStorage.getItem(STORAGE_KEY)
		
		if (rets === null) {
			return []
		}
		return JSON.parse(rets)
	}
	catch(e){
		return []
	}
}

const addCart = (value) => {
	let rets = getStorage()
	
	rets.push(value)
	
	window.localStorage.setItem(STORAGE_KEY, JSON.stringify(rets))
	
	return rets	
}

const minusCart = (value) => {
	let rets = getStorage()
	let idx = rets.indexOf(value)
	
	if (idx !== -1){
		rets.splice(idx, 1)
		window.localStorage.setItem(STORAGE_KEY, JSON.stringify(rets))
	}

	
	return rets	
}

const render = () => {
	let rets = getStorage()
	
	if (rets.length){
		$("#num").html(rets.length).show()
	}
	else {
		$("#num").hide()
	}
	
	$(".list li").each((i,el) => {
		if (rets.includes(i)){
			$(el).find("a:nth-child(1)").css("visibility", "hidden")
			$(el).find("a:nth-child(2)").css("visibility", "visible")
			
		}
		else {
			$(el).find("a:nth-child(1)").css("visibility", "visible")
			$(el).find("a:nth-child(2)").css("visibility", "hidden")
			
		}
	})
}

$(".list a").on("click", (e)=> {
	let opIdx = $(e.target).parent().find("a").index(e.target)
	let line = $(e.target).parent().parent()
	let idx = $(".list li").index(line)
	
	opIdx === 0 ? addCart(idx) : minusCart(idx)
	
	render()
	
	return false
})

window.addEventListener('storage', (e) => {
	render()
})

render()
複製代碼

其中,下面這行代碼是實現的關鍵:ide

window.addEventListener('storage', (e) => {
	render()
})
複製代碼

當咱們註釋掉這個語句,咱們的頁面同步就不能運行了。函數

讀者能夠打開多個Tab並觀察頁面的變化https://jsbin.com/radekilosu/1/edit?html,css,js,output。ui

實際上,這個事件e上還帶有不少信息,方便編程時,對於事件作精確的控制。

字段 含義
key 發生變化的storageKey
newValue 變換後新值
oldValue 變換前原值
storageArea 相關的變化對象
url 觸發變化的URL,若是是frameset內,則是觸發幀的URL

上述各值都是隻讀的。

還有一點沒有解決掉,就是觸發storage變化的本頁面,不能接收這個值,這個通常狀況下是沒問題。固然,爲了一致性,咱們能夠自行new一個事件,在發生時候主動觸發它。

此時咱們能夠包裝一個新的Storage對象:

var Storage = {
    setItem : function(k,v){
      localStorage.setItem(k,v);
    },
    removeItem : function(k){
      localStorage.removeItem(k);
    },
    clear: function (){},
    getItem: function(k){}
}
複製代碼

此時,咱們再包裝一個函數:

function dispatchMe(key, oldval, newval, url, storage){
    var se = document.createEvent("StorageEvent");
    se.initStorageEvent('storage', false, false, key, oldval, newval, url, storage);
    window.dispatchEvent(se);
}
複製代碼

此時,咱們只須要在setItem、removeItem、clear中獲取對應的值,並手動調用一下dispatchMe,同時把和localStorage打交道的地方改成調用咱們包裝的Storage便可。

參考資料

  1. developer.mozilla.org/en-US/docs/…
  2. www.cnblogs.com/cczw/p/3196…

關於奇舞週刊

《奇舞週刊》是360公司專業前端團隊「奇舞團」運營的前端技術社區。關注公衆號後,直接發送連接到後臺便可給咱們投稿。

相關文章
相關標籤/搜索