乐趣区

关于javascript:解决sessionStorage不能跨标签页共享

用户在一个标签页已登录,再关上多个标签页,此场景下将 token 保留在 sessionStorage 中将会带来很差的用户体验,每次开启一个标签页都会要求用户从新登录。

sessionStorage 顾名思义是针对一个 session 的数据存储,生命周期为以后窗口,一旦窗口敞开,那么存储的数据将被清空。最初还有一个很次要的区别同一浏览器的雷同域名和端口的不同页面间能够共享雷同的 localStorage,然而不同页面间无奈共享 sessionStorage 的信息。

解决:
在 index.html 中减少以下代码,复制全副 sessionStorage 内材料

(function(){
    // 判断以后页面是否存在 sessionStorage
    if (!sessionStorage.length) {
        // 这个调用能触发指标事件,从而达到共享数据的目标(若不存在则加上一个 localStorage Item,key=getSessionStorageData)localStorage.setItem('getSessionStorageData', Date.now());
    };

    // 该事件是外围,减少 window 监听事件 
    window.addEventListener('storage', function(event) {
         // 已存在的标签页会收到这个事件,如果监听到的事件 key 是 getSessionStorageData
         if (event.key == 'getSessionStorageData') {
             // 再新增一个 localStorage Item,key=sessionStorageData,value 就是以后的 sessionStorage
            localStorage.setItem('sessionStorage', JSON.stringify(window.sessionStorage));
            // 删除 localStorage 中 key=sessionStorageData 的 item
            localStorage.removeItem('sessionStorage');

        } 
        if (event.key == 'sessionStorageData' && !sessionStorage.length) {
            // 新开启的标签页会收到这个事件,把 sessionStorageData 的材料 parse 进去
            const data = JSON.parse(event.newValue);
            //  赋值到以后页面的 sessionStorage 中
            for (key in data) {window.sessionStorage.setItem(key, data[key]);
            }
        }
    });
})();

整体流程:
1、判断页面是否存在 sessionStorage,并加上 store 事件的监听;
2、若不存在,就把本来的 sessionStorage 内的材料复制到 localStorage 中并取名为 sessionStorageData;
3、若 storage 事件监听到 key 为 sessionStorageData 的事件,就把内容通过 for 赋值到页面 sessionStorage 中;

为什么复制到 localStorage 后又间接删除?
因为 window 增加了监听事件

window.addEventListener('storage', ..)

这就意味着每次 storage 事件被触发的时候都会执行,所以当 setItem(‘sessionStorage’)的时候,也会接管到事件,
代表着

window.localStorage.removeItem('sessionStorage')

其实是产生在 sessionStorage 被写入之后的事件了,所以能够同时写入和删除,不留下 localSorage 的记录。

新开的页面为什么会有 sessionStorage 能够提供复制?
查问 API(Using the Web Storage API|MDN)后晓得,各标签只有是同域名,有对 storage 动作时全副都会被连动,storage 事件能够做到同域名的状态监测。

storage 事件的测试
轻易开两个同域名的标签页后,别离开启开发者工具:
1、在 A 标签页下

window.addEventListener('storage', (event) => console.log(event));

2、在 B 标签页下

window.localStorage.setItem('storageTest', 'test');

3、再回头看 A 标签页,就会发现曾经被监听到 storage 事件了。
通过这样的事件监听,就能够达到由 localSorage 传递 sessionStorage 的目标。

对于登出
登出时同步革除所有标签页的 sessionStorage 并 reload 页面

(function(){
    // 判断以后页面是否存在 sessionStorage
    if (!sessionStorage.length) {
        // 这个调用能触发指标事件,从而达到共享数据的目标(若不存在则加上一个 localStorage Item,key=getSessionStorageData)localStorage.setItem('getSessionStorageData', Date.now());
    };

    // 该事件是外围,减少 window 监听事件 
    window.addEventListener('storage', function(event) {
         // 已存在的标签页会收到这个事件,如果监听到的事件 key 是 getSessionStorageData
         if (event.key == 'getSessionStorageData') {
             // 再新增一个 localStorage Item,key=sessionStorageData,value 就是以后的 sessionStorage
            localStorage.setItem('sessionStorage', JSON.stringify(window.sessionStorage));
            // 删除 localStorage 中 key=sessionStorageData 的 item
            localStorage.removeItem('sessionStorage');

        } 
        if (event.key == 'sessionStorageData' && !sessionStorage.length) {
            // 新开启的标签页会收到这个事件,把 sessionStorageData 的材料 parse 进去
            const data = JSON.parse(event.newValue);
            //  赋值到以后页面的 sessionStorage 中
            for (key in data) {window.sessionStorage.setItem(key, data[key]);
            }
        }
        // ===== 加上面这段 =====
        if (event.key === 'logout') {
            // 接管到 logout 事件,进行 sessionStorage 的革除和页面 reload
            window.sessionStorage.clear();
            window.location.clear();}
    });
})();

其余
即便这样看起来 ok,但还是有缺点
1、Chrome,FireFox 的复原分页性能会将 sessionStorage 的材料一起复原,这可能会导致一些安全性问题(不过相较于 localStorage,这应该不算问题)
2、这些数据是标签页被开启的同时获取的,意味着如果你的 sessionStorage 贮存着常常被变动的材料,必须再写一些事件去拦挡和复制,因为 storage 事件不会监听到其余页面的 sessionStorage 变动.

退出移动版