現代前端項目多爲單頁Web應用(SPA),在單頁Web應用中路由是其中的重要環節。
SPA 是 single page web application 的簡稱,譯爲單頁Web應用。
簡單的說 SPA 就是一個WEB項目只有一個 HTML 頁面,一旦頁面加載完成,SPA 不會由於用戶的操做而進行頁面的從新加載或跳轉。 取而代之的是利用 JS 動態的變換 HTML 的內容,從而來模擬多個視圖間跳轉。css
簡單的說,就是在保證只有一個 HTML 頁面,且與用戶交互時不刷新和跳轉頁面的同時,爲 SPA 中的每一個視圖展現形式匹配一個特殊的 url。在刷新、前進、後退和SEO時均經過這個特殊的 url 來實現。
咱們須要實現下滿兩點:html
hash 模式和 history 模式,就是用來實現上面功能的前端
在url後面加上#,如http://127.0.0.1:5500/前端路由/hash.html#/page1
這個url後面的#/page1
就是hash值html5
基於以上三點咱們能夠寫一個路由實例web
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <ul> <li><a href="#/">/</a></li> <li><a href="#/page1">page1</a></li> <li><a href="#/page2">page2</a></li> </ul> <div class="content-div"></div> </body> <script> class RouterClass { constructor() { this.routes = {}; // 記錄路徑標識符對應的cb this.currentUrl = ""; // 記錄hash只爲方便執行cb window.addEventListener("load", () => this.render()); window.addEventListener("hashchange", () => this.render()); } /* 初始化 */ static init() { window.Router = new RouterClass(); } /* 註冊路由和回調 */ route(path, cb) { this.routes[path] = cb || function() {}; } /* 記錄當前hash,執行cb */ render() { this.currentUrl = window.location.hash.slice(1) || "/"; this.routes[this.currentUrl](); } } RouterClass.init(); const ContentDom = document.querySelector(".content-div"); const changeContent = content => (ContentDom.innerHTML = content); Router.route("/", () => changeContent("默認頁面")); Router.route("/page1", () => changeContent("page1頁面")); Router.route("/page2", () => changeContent("page2頁面")); </script> </html>
History 接口容許操做瀏覽器的曾經在標籤頁或者框架裏訪問的會話歷史記錄。能夠參考下兩篇文章對history的說明
https://css-tricks.com/using-the-html5-history-api/
https://developer.mozilla.org/zh-CN/docs/Web/API/History
下面介紹在這個模式下須要用到的apiajax
history.go(n)
:路由跳轉幾步,n爲2往前跳轉2個頁面,-2日後跳轉兩個頁面history.back()
:路由後退,至關於 history.go(-1)
,用戶可點擊瀏覽器左上角的後退按鈕模擬此方法history.forward()
:路由前進,至關於 history.go(1)
,用戶可點擊瀏覽器左上角的前進按鈕模擬此方法history.pushState()
:添加一條路由歷史記錄,若是設置跨域網址則報錯segmentfault
history.pushState
用於在瀏覽歷史中添加歷史記錄,可是並不觸發跳轉,此方法接受三個參數,依次爲:
state
:一個與指定網址相關的狀態對象,popstate
事件觸發時,該對象會傳入回調函數。若是不須要這個對象,此處能夠填null
。
title
:新頁面的標題,可是全部瀏覽器目前都忽略這個值,所以這裏能夠填null
。
url
:新的網址,必須與當前頁面處在同一個域。瀏覽器的地址欄將顯示這個網址。
當活動歷史記錄條目更改時,將觸發popstate事件。若是被激活的歷史記錄條目是經過對history.pushState()的調用建立的,或者受到對history.replaceState()的調用的影響,popstate事件的state屬性包含歷史條目的狀態對象的副本。
須要注意的是調用history.pushState()或history.replaceState()不會觸發popstate事件。只有在作出瀏覽器動做時,纔會觸發該事件,如用戶點擊瀏覽器的回退按鈕(或者在Javascript代碼中調用history.back())後端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <ul> <li><a href="/">/</a></li> <li><a href="/page1">page1</a></li> <li><a href="/page2">page2</a></li> </ul> <div class="content-div"></div> </body> <script> class RouterClass { constructor(path) { this.routes = {}; // 記錄路徑標識符對應的cb history.replaceState({ path }, null, path); // 進入狀態 this.routes[path] && this.routes[path](); window.addEventListener("popstate", e => {// 當用戶點擊瀏覽器的前進或者後退觸發 console.log(e.state) const path = e.state && e.state.path; this.routes[path] && this.routes[path](); }); } /* 初始化 */ static init() { window.Router = new RouterClass(location.pathname); } /* 註冊路由和回調 */ route(path, cb) { this.routes[path] = cb || function() {}; } /* 跳轉路由,並觸發路由對應回調 */ go(path) { history.pushState({ path }, null, path); console.log(history); this.routes[path] && this.routes[path](); } } RouterClass.init(); const ul = document.querySelector("ul"); const ContentDom = document.querySelector(".content-div"); const changeContent = content => (ContentDom.innerHTML = content); Router.route("/", () => changeContent("默認頁面")); Router.route("/page1", () => changeContent("page1頁面")); Router.route("/page2", () => changeContent("page2頁面")); ul.addEventListener("click", e => { console.log(e.target.tagName); if (e.target.tagName === "A") { e.preventDefault(); Router.go(e.target.getAttribute("href")); } }); </script> </html>
Hash 模式是使用 URL 的 Hash 來模擬一個完整的 URL,所以當 URL 改變的時候頁面並不會重載。History 模式則會直接改變 URL,因此在路由跳轉的時候會丟失一些地址信息,在刷新或直接訪問路由地址的時候會匹配不到靜態資源。所以須要在服務器上配置一些信息,讓服務器增長一個覆蓋全部狀況的候選資源,好比跳轉 index.html 什麼的api
優勢跨域
ie8
)hash
的路由實現ajax
請求之外,不會發起其餘請求缺點
hash
部份內容,致使後臺沒法取得url
中的數據,典型的例子就是微信公衆號的oauth
驗證優勢
url
中的參數。後端能夠拿到這部分數據browser
的路由實現history.state
來獲取當前url
對應的狀態信息缺點
hash
路由(只兼容到IE10
)html
文檔實例來源:http://www.javashuo.com/article/p-ybhejxib-r.html
官方文檔:https://developer.mozilla.org/en-US/docs/Web/API/History_API
優缺點比較:https://juejin.im/post/5b5ec5...