功能描述:在瀏覽器退出時(全部tab關閉時)退出登陸瀏覽器
需求來源:支持相似傳統網頁登陸時的remember me選項併發
背景:Meteor應用中,用戶登陸後,會在瀏覽器的localStorage保存resume token, 因此下次再使用該瀏覽器打開同一meteor應用時,會自動登陸。有時,咱們但願應用支持在瀏覽器退出時(全部tab關閉時)即退出登陸,然而meteor被沒有對這項功能的原生支持,須要咱們本身實現。spa
要點:如何檢測tab關閉,如何檢測全部tab關閉code
調用Meteor.logout()blog
咱們但願tab關閉時退出登陸,那麼咱們得有方法檢測tab關閉。咱們能夠向瀏覽器beforeunload事件註冊監聽。例如:token
$(window).on('beforeunload', function () { Meteor.logout();
});
依據meteor的登陸機制,在如何用戶在同一瀏覽器打開多個tab,那麼他們的登陸狀況是相同的。若是僅依靠上述代碼,那麼任意tab關閉時,將致使用戶退出登陸。咱們但願的邏輯是,瀏覽器關閉,或者全部該應用的tab關閉時,才退出登陸。事件
或許有更好的解決方案,這裏僅介紹一下個人一種解決方案:利用瀏覽器的localStorage,記錄當前應用打開的tab數目,當關閉tabrem
$(window).on('load', function () { let count = Meteor._localStorage.getItem(openTabCountKey); count = count ? Number(count) + 1 : 1; Meteor._localStorage.setItem(openTabCountKey, count); }); $(window).on('beforeunload', function () { Meteor._localStorage.setItem(openTabCountKey, Number(Meteor._localStorage.getItem(openTabCountKey)) - 1); });
這裏有幾個小的細節須要注意:字符串
在記錄了tab打開數量以後,咱們能夠修正一下上述代碼:get
$(window).on('beforeunload', function () { let count = Number(Meteor._localStorage.getItem(openTabCountKey));if (!(count > 0)) { Meteor.logout(); } });
有了上述代碼,應用應該具備咱們預期的功能:當瀏覽器關閉時,或全部該應用的tab關閉時,退出登陸。
而然,聰明的你可能會發現,再次打開該應用時,控制檯顯示一段報錯提示:……(大意是你被服務端強制退出登陸)
若是你查看一下Meteor.logout源碼,應該能夠知道緣由:該方法先調用了服務端方法,在服務端清除相關resume token,而後客戶端在回調中再清除本地保存的resume token。
而然,雖然服務端清除了resume token,但咱們沒有等到客戶端響應就關閉了tab(關閉了應用),因此沒辦法在回調中執行客戶端相關的清理工做。所以,咱們須要顯示地、同步地執行客戶端清理工做。修正後的代碼以下:
$(window).on('beforeunload', function () { let count = Number(Meteor._localStorage.getItem(openTabCountKey));if (!(count > 0) && shouldLogout) { Meteor.logout(); Accounts.makeClientLoggedOut(); } });
添加一些方法,以支持設置與取消該特性。
相關代碼以下:
/** * logout when all tabs are closed * @param {Boolean} setIt - default true */ logoutOnClose(setIt = true) { if (setIt) { Meteor._localStorage.setItem(oncloseLogoutKey, true); } else { Meteor._localStorage.removeItem(oncloseLogoutKey); } }
willLogoutOnClose() { return Boolean(Meteor._localStorage.getItem(oncloseLogoutKey)) }
$(window).on('load', function () { let count = Meteor._localStorage.getItem(openTabCountKey); count = count ? Number(count) + 1 : 1; Meteor._localStorage.setItem(openTabCountKey, count); }); $(window).on('beforeunload', function () { Meteor._localStorage.setItem(openTabCountKey, Number(Meteor._localStorage.getItem(openTabCountKey)) - 1); });
$(window).on('beforeunload', function () { let count = Number(Meteor._localStorage.getItem(openTabCountKey)); let shouldLogout = Boolean(Meteor._localStorage.getItem(oncloseLogoutKey)); if (!(count > 0) && shouldLogout) { Meteor.logout(); Accounts.makeClientLoggedOut(); } });