樹醬但願將前端的樂趣帶給你們 本文已收錄 github.com/littleTreem… 喜歡就star✨html
談到路由,通常分爲前端路由和後端路由兩種,後端路由指的當用戶經過瀏覽器切換不一樣URL時,都會向服務器發起資源請求,服務器經過後端路由匹配以後根據不一樣URL返回不一樣頁面,而前端路由則將瀏覽器與服務器交互(頁面跳轉的URL規則匹配)的任務交給前端來作前端
目前單頁應用(SPA)成爲目前前端應用的主流,而大型單頁應用的一個大特徵是,由前端路由來控制頁面的跳轉,經過url的切換,在不請求服務器的前提,更新頁面視圖,這裏以vue-router爲例分析,前端路由模式主要包括兩種:hash模式和history模式vue
hash模式便是經過 hash 值(相似錨點)的變化,瀏覽器不用向服務器發起請求,也就無需刷新頁面。而瀏覽器是怎麼監聽變化的呢?就是經過url中hash 值的變化,此時還好觸發 hashchange 事件,經過此事件的觸發咱們就能夠清晰知道hash發生了什麼變化html5
假設你瀏覽器訪問的url地址是 http://127.0.0.1/#/test 那麼經過 location.hash 獲取的hash值爲 #/testwebpack
致使路由的變化無非是三種狀況:刷新頁面、瀏覽器返回操做、新連接跳轉,下面是具體流程圖👇git
那hash模式下監聽路由變化實現的原理是怎麼樣的呢?github
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
function onHashChange(){
// todo 匹配 hash 作 dom 更新操做
}
複製代碼
有興趣的童鞋能夠研究vue-router關於hash類的具體源碼實現 點我到達火箭web
自HTML5新標準出臺,pushState和replaceState是HTML5的新接口,經過這兩個 API 能夠改變 url 地址且不會發送請求,前端路由今後了多了另一種模式History,並且經過這種模式再也不須要在URL添加#符號,也能讓URL顯得更加優美正則表達式
咱們先看看window.history對象裏面有什麼vue-router
History.pushState
在不刷新瀏覽器的狀況下,建立新的瀏覽記錄並插入瀏覽記錄隊列中,當刷新頁面,頁面內容不變但地址發生了變化,該API可傳入三個參數,分別是
window.history.pushState({data: "test"}, "", 'http://127.0.0.1/test');
複製代碼
History.replaceState:
的使用與 history.pushState() 相似,區別在於pushState會增長一條新的歷史記錄,而replaceState則會替換當前的歷史記錄,把當前的歷史記錄改爲目標地址
window.history.replaceState({data: "test"}, "", 'http://127.0.0.1/test');
複製代碼
popstate
當用戶發起返回操做或者執行history.go()或history.forward()等操做時,纔會觸發popstate
window.addEventListener('popstate', e => {
//todo
});
複製代碼
講完history模式涉及到接口,樹醬聊聊配置history模式須要注意的事項,這種模式相比hash模式還須要配置後端,若是後臺沒有正確的配置,當用戶在瀏覽器直接刷新 http://127.0.0.1/#/test 就會返回 404,那如何解決這個問題呢 🤔️
你須要在Nginx配置文件添加劇定向 附上 history vue-router官方文檔
location / {
try_files $uri $uri/ /index.html;
}
複製代碼
Vue-router History模式下的流程圖以下所示
有興趣Vue-router關於history類的具體源碼實現 點我到達火箭
聊聊vue-router的一些應用場景
路由攔截能夠用來做爲前端鑑權入口,好比判斷是不是已登陸狀態
mport Vue from 'vue' import Router from 'vue-router' Vue.use(Router) const router = new Router({ routes: [ { path: '/home','' component: () => import('@/components/Home') } },{ path: '/login', name: 'login', component: (resolve) => { component: () => import('@/components/Login') } }}] }) // 判斷是否須要登陸權限 以及是否登陸 router.beforeEach((to, from, next) => { if (to.matched.some(res => res.meta.requireAuth)) { // 判斷路由是否須要登陸權限 if (localStorage.getItem('item')) { //判斷是否有token next() } else {// 沒登陸則跳轉到登陸界面 next({ path: '/login', query: {redirect: to.fullPath} }) } } else { next() } }) 複製代碼export default router 複製代碼
懶加載,顧名思義就是等須要再加載,在SPA應用中,若是不經過懶加載加載組件的方式,會致使webpack打包出來的文件體制過大,進而影響用戶體驗
export default new Router({
routes: [
{
path: '/home',
name: 'home',
component: () => import('@/components/Home') # 懶加載引入組件
}
]
});
複製代碼
你是否還在煩惱如何按不一樣模塊不一樣功能管理不一樣路由,這裏要推薦使用 require.context()
不一樣功能模塊區分,再經過require.context 導出全部路由
require.context() 它容許傳入一個目錄進行搜索,一個標誌表示是否也應該搜索子目錄,以及一個正則表達式來匹配文件,當你構建項目時,webpack會處理require.context的內容
require.context()可傳入三個參數分別是:
directory :讀取文件的路徑
useSubdirectories :是否遍歷文件的子目錄
regExp: 匹配文件的正則
實際應用以下👇
routes導出來結果是這樣
固然本來的定義路由的方式也變了
/*
* 我的中心路由模塊(user)
* @Author: tree
* @Date: 2019-11-06 20:20:51
*/
export default [
{
path: '/user/info',
name: 'personalInfo',
component: () => import('@/views/user/info.vue'),
meta: { title: '帳號信息', keepAlive: false, showHeader: true },
},
{
path: '/user/security',
name: 'security',
component: () => import('@/views/user/security.vue'),
meta: { title: '安全設置', keepAlive: false, showHeader: true },
},
];
複製代碼