创建一个storageevent事件_谈谈StorageEvent
編者按:本文作者 劉觀宇,360 奇舞團(tuán)高級(jí)前端工程師、技術(shù)經(jīng)理,W3C CSS 工作組成員。
紛紛紅紫已成塵,布谷聲中夏令新。夾路桑麻行不盡,始知身是太平人。 ——宋.陸游 《初夏絕句》
我們?cè)陂_發(fā)多Tab應(yīng)用時(shí)候,常常會(huì)遇到多個(gè)Tab狀態(tài)同步的問題。
想象如下場景:用戶主界面,顯示用戶購物車內(nèi)待結(jié)算的商品總數(shù)。此時(shí),用戶可能打開多個(gè)Tab。當(dāng)用戶添加新商品到購物車的時(shí)候,需要更新購物車的數(shù)量。
此時(shí),當(dāng)前頁面需要向服務(wù)器發(fā)起請(qǐng)求,在得到添加成功響應(yīng)的時(shí)候,可以更新用戶界面。為了兼顧體驗(yàn)和可靠性,如果確信添加成功概率比較高的時(shí)候,也可以先更新界面,當(dāng)多數(shù)返回錯(cuò)誤的時(shí)候,可以給用戶界面做狀態(tài)回滾。為了下次展示方便,我們還會(huì)把這個(gè)數(shù)據(jù)寫到LocalStorage里面。用戶再次打開時(shí)候,可以優(yōu)先從localStorage中取值。
當(dāng)前頁面解決了,那么如果同時(shí)打開多個(gè)Tab該如何解決呢?這里使用StorageEvent可能是一種代價(jià)較小的解決方案。
StorageEvent是什么呢?
是一種Event,可以通過標(biāo)準(zhǔn)的Event監(jiān)聽器操作。
當(dāng)storage變化時(shí)候,事件會(huì)被派發(fā)到所有同域下的其他頁面。
觸發(fā)變化的當(dāng)前頁面,沒有事件派發(fā)。
這里有一個(gè)簡單的示例可以展示這個(gè)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()
其中,下面這行代碼是實(shí)現(xiàn)的關(guān)鍵:
window.addEventListener('storage',?(e)?=>?{
????render()
})
當(dāng)我們注釋掉這個(gè)語句,我們的頁面同步就不能運(yùn)行了。
讀者可以打開多個(gè)Tab并觀察頁面的變化 https://jsbin.com/radekilosu/1/edit?html,css,js,output 。
實(shí)際上,這個(gè)事件e上還帶有很多信息,方便編程時(shí),對(duì)于事件做精確的控制。
| key | 發(fā)生變化的storageKey |
| newValue | 變換后新值 |
| oldValue | 變換前原值 |
| storageArea | 相關(guān)的變化對(duì)象 |
| url | 觸發(fā)變化的URL,如果是frameset內(nèi),則是觸發(fā)幀的URL |
上述各值都是只讀的。
還有一點(diǎn)沒有解決掉,就是觸發(fā)storage變化的本頁面,不能接收這個(gè)值,這個(gè)一般情況下是沒問題。當(dāng)然,為了一致性,我們可以自行new一個(gè)事件,在發(fā)生時(shí)候主動(dòng)觸發(fā)它。
此時(shí)我們可以包裝一個(gè)新的Storage對(duì)象:
var?Storage?=?{
????setItem?:?function(k,v){
??????localStorage.setItem(k,v);
????},
????removeItem?:?function(k){
??????localStorage.removeItem(k);
????},
????clear:?function?(){},
????getItem:?function(k)
}
此時(shí),我們?cè)侔b一個(gè)函數(shù):
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);
}
此時(shí),我們只需要再setItem、removeItem、clear中獲取對(duì)應(yīng)的值,并手動(dòng)調(diào)用一dispatchMe,同時(shí)把和localStorage打交道的地方改為調(diào)用我們的新對(duì)象即可。
參考資料
https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
https://www.cnblogs.com/cczw/p/3196195.html
關(guān)于奇舞周刊
《奇舞周刊》是360公司專業(yè)前端團(tuán)隊(duì)「奇舞團(tuán)」運(yùn)營的前端技術(shù)社區(qū)。關(guān)注公眾號(hào)后,直接發(fā)送鏈接到后臺(tái)即可給我們投稿。
總結(jié)
以上是生活随笔為你收集整理的创建一个storageevent事件_谈谈StorageEvent的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用友 无法正确解析服务器,用友T3软件登
- 下一篇: java题霸_牛客题霸每日一题 + NC