傳統的 web 項目中,多數是多頁應用,即每次頁面跳轉的時候,後臺服務器都會給返回一個新的 html
和與之相關的 css
和 js
資源,例如熟悉的 JSP
,這種類型的網站也就是多頁網站,也叫作多頁應用。這種應用最明顯的缺點就是頁面切換的響應速度慢、靜態資源的重複加載等。css
而單頁應用(SPA)在頁面跳轉的時候,並不須要請求新的 html
、css
和 js
等資源,這樣就節省了不少 http
請求,加快了頁面切換的速度。但也帶來了一個明顯的缺點就是第一次加載應用的時候就要獲取到全部的頁面,致使首屏加載時間較長。幸運的是,服務端渲染(SSR)技術可以很好的解決這個問題。html
綜合來看,對於中小規模的應用,在現在強調先後端分離的時代,單頁應用是很好的選擇。接下來的分享是我在利用 vue
、vue-router
和 vuex
開發單頁應用中遇到的一些問題以及對應的解決方法。前端
單頁應用不須要爲每一個頁面都新建一個 html
文件和若干個 css
和 js
文件,頁面切換不須要後端的控制,看起來貌似對前端開發人員很友好,但實際狀況是,對於大多數單頁應用而言,前端開發人員須要考慮的東西更多了。主要在於頁面訪問權限的控制,例如在哈希模式下,用戶能夠手動改變url的哈希值來訪問不一樣的路由,但在實際應用中,對於用戶的這種操做是須要進行判斷控制的,例如,某些路由須要登陸以後纔有權限訪問、某些路由對應的頁面須要特殊的權限才能訪問等。vue
我將單頁應用中的頁面類型分爲如下兩種:web
登陸頁面的特殊之處在於,登陸頁面只應該在用戶須要進行登陸操做的時候纔對其可見,也就是說,若用戶的登陸狀態沒有過時,則用戶不能訪問登陸頁面的路由。ajax
在 vue
應用中,一般會在 mounted
方法中發送 ajax
請求獲取數據。但在單頁應用中,用戶能夠改變 url 中的哈希值來訪問不一樣的路由,但對於某些頁面,例如我的中心等,須要用戶登陸以後才能獲取到有效的數據進行展現。雖然有一種簡單的處理方法:容許用戶訪問這個路由的頁面,但 ajax
獲取不到有效數據,但顯然不是最好的解決辦法。比較好的作法是,經過 vue-router
的生命週期函數判斷進入這些路由前,用戶是否已經登陸,沒有登陸則重定向到登陸頁面的路由。vue-router
router.beforeEach((to, from, next) => { if (to.path == '/login') { // 訪問登陸頁面的路由 if (login) { // 登陸狀態有效,重定向到首頁 next('/'); } else { // 須要登陸 next(); } } else { // 訪問其餘的路由 if (login) { // 登陸狀態有效,容許訪問 next(); } else { // 須要登陸,重定向到登陸頁面 next('/login'); } } })
通過上面的分析,問題最終都指向了 前端如何判斷用戶的登陸狀態。vuex
一般狀況下,前端只負責發送請求,根據響應顯示頁面的不一樣內容,然後端會經過 sessionId
或者 token
來判斷用戶的登陸狀態是否過時。那麼前端有哪些辦法(哪些地方) 記錄(保存)用戶的登陸狀態是否有效這個數據呢?後端
sessionStorage
、localStorage
和 cookie
是前端經常使用的客戶端存儲方法。瀏覽器
做爲讓後端有記憶能力的解決辦法,一般會攜帶一些後端判斷請求是來着於誰的信息,如 sessionId
/ token
,如前面所說,這些信息仍是由後端判斷是否過時,通常不會在 cookie
中直接存儲登陸狀態是否有效。
存儲在瀏覽器中,能夠在用戶登陸成功以後利用 setItem
保存一個屬性,在路由的生命週期函數 beforeEach
中經過 getItem
判斷是否已經登陸。實現簡單,但存在的問題較多:
sessionStorage
自己的過時時間決定了用戶的登陸狀態與 sessionStorage
的有效期同步。例如關閉瀏覽器以後都得從新登陸,而無論後端是否設置了 cookie
的 expire
屬性。
sessionStorage
還有效,致使用戶本能訪問頁面,只是沒有數據。用戶只能經過一些操做讓 sessionStorage
失效(關閉瀏覽器窗口從新進)sessionStorage
沒有了,致使用戶須要從新登陸。sessionStorage
是可讀可寫的,在瀏覽器的調試工具中能夠輕鬆執行 clear
等方法,也能輕鬆讀取到 setItem
的值,低安全性也決定了 sessionStorage
不能存儲重要信息。除了過時時間與 sessionStorage
不同,其餘的功能都相似。
在應用中存儲,一般就是在 vuex
中記錄用戶是否登陸。在路由的生命週期函數 beforeEach
中讀取這個數據來判斷用戶的登陸狀態是否有效。那麼問題來了:
個人解決辦法是:經過發送一個請求判斷登陸狀態是否有效。對於獲取數據的請求,若返回值中的信息表明須要從新登陸了,則清空 vuex
並重定向到登陸頁面。
來看看利用 vuex
記錄登陸狀態時會遇到的全部狀況以及處理辦法:
router.beforeEach(async (to, from, next) => { if (to.path == '/login') { // 訪問登陸頁面的路由 if (store.login) { // 登陸狀態有效,重定向到首頁 // 這種狀況一般是用戶手動修改了 url 中的 hash next('/'); } else { // 發送 ajax 判斷登陸狀態是否有效 const login = await ajax(); if (login) { // 修改 store,重定向到首頁 store.commit('login', true); next('/'); } else { next(); } } } else { // 訪問其餘的路由 if (store.login) { // 登陸狀態有效,容許訪問 next(); } else { // 尚未通過登陸頁面就訪問其餘路由,這種狀況一般也是用戶手動修改了 url 中的 hash // 發送 ajax 判斷登陸狀態是否有效 const login = await ajax(); if (login) { // 修改 store,容許訪問 store.commit('login', true); next(); } else { next('/login'); } } } })
另外,對於每個獲取數據的請求,若後端的返回值中表明用戶的登陸狀態已通過期,則改變 vuex
中的登陸狀態並重定向到登陸頁:
store.commit('login', false); location.href = '/#/login'; location.reload();