前言
Safari開啟無痕模式後,localStorage和sessionStorage為空,對其進行set操作也會報錯,也就是說這種情況下,storage是被禁止使用了。接下來說一下解決方法。
解決方案
我們專案框架上的解決方法是對storage進行一層封裝,遇到這種開啟無痕模式的情況,會定義一個window的全域性變數,把之前準備存放到storage的內容改為存到這個全域性變數中。
注意,無痕模式下localStorage和sessionStorage物件本身依然是存在的,只是呼叫setItem方法是會報錯。下面是無痕模式下報錯的截圖:
所以正確的判斷程式碼應該是這樣:
try {
sessionStorage.setItem('private_test', 1);
} catch (e) {
//無痕模式
}
複製程式碼
我們會另外定義一個NameStorage物件,在原生storage失效時使用:
// 隱私模式下面,把臨時值存到window.name中去
function NameStorage(type) {
this.store = NameStorage[type];
}
Object.assign(NameStorage.prototype, {
getItem: function(key) {
return this.store[key];
},
setItem: function(key, value) {
this.store[key] = value;
this._saveNameValue();
},
removeItem: function(key) {
delete this.store[key];
this._saveNameValue();
},
clear: function() {
this.store = {};
this._saveNameValue();
},
_saveNameValue: function() {
var ret = {
session: NameStorage.session,
local: NameStorage.local
}
window.name = JSON.stringify(ret);
}
});
複製程式碼
上面會把所有的local和session資料儲存到window.name上去,然後在每個頁面啟動時,呼叫一下keepName方法,把window.name的資料拿下來放到NameStorage上面。這時候,只需要呼叫new NameStorage('local')來代替localStorage進行操作就行了
function keepName () {
if (keepName.done) {
return;
}
var ret;
if (window.name) {
try {
ret = JSON.parse(window.name);
} catch (e) {
ret = {};
}
}
if (!_.isPlainObject(ret)) {
ret = {};
}
if (!ret.session) {
ret.session = {};
}
if (!ret.local) {
ret.local = {};
}
NameStorage.session = ret.session;
NameStorage.local = ret.local;
keepName.done = true;
}
複製程式碼
另外一些補充
● 無痕模式下,localStorage和sessionStorage的報錯資訊是:QuotaExceededError,code為22,這個其實是storage儲存空間用完了報的錯,就比如當前瀏覽器storage記憶體為5mb,你已經儲存了5mb的資料後,再進行setItem操作就會報這個錯誤。
● 所以我猜想無痕模式下,瀏覽器是把storage的記憶體先清空,然後再設定最大值為0,這樣呼叫setItem就直接報錯了。
● 另外無痕模式下cookie是可以使用的,大概因為cookie是跟伺服器有關,而storage是屬於瀏覽器的特性吧。
● 最後還有一種情況,就是無痕模式下開啟了某個頁面,然後把瀏覽器關閉再開啟,這個時候會開啟訪問的頁面,但是window.name已經丟失了,所以就拿不到以前儲存的資料了。這種情況只能頁面做容錯處理了。