在單頁面應用程序中,先後端採用了徹底分離的方法,所以在前端實現路由的切換很是的重要。同時前端實現路由能夠減小請求數,緩解後端的壓力。在單頁面中的路由主要有兩種實現方法,一種是經過h5的history api來實現,還有一種是hash來實現。javascript
history的方法主要是應用了幾個H5的histroy API:css
在history中建立一個新的訪問記錄,不能跨域,且不形成頁面刷新,stateData爲當前頁面的一些信息在觸發popstate事件的時候能夠調用;title爲網頁的標題;url是瀏覽器中顯示的網址。html
修改當前的訪問記錄,不能跨域,且不形成頁面刷新前端
當回到頁面前一頁或者後一頁的時候觸發java
這張圖表示了這些api的具體操做。jquery
pushState主要就是向當前頁面的後面添加一個新的頁面,新的頁面地址是第三個參數。 replaceState是把當前頁面的地址替換成他的第三個參數,history並不會記錄以前的地址 這兩個方法都不能進行頁面的刷新,因此須要在調用方法的時候執行一下相關路由變化的操做,從而達到頁面不切換的效果更改頁面的單頁面效果。
所以只要在頁面跳轉的時候改爲pushState而後執行當前頁面的加載函數,就能夠實現不刷新的頁面跳轉了如: 原來地址是:https://www.baidu.com 而後點擊了按鈕進行頁面跳轉就執行函數: history.pushState(data, title, 'https://www.baidu.com/test') 而後瀏覽器上面的地址已經變成了https://www.baidu.com/test而後同時還有返回的按鈕 而後調用一下test頁面的渲染方法
這樣子會存在一個問題,就是當頁面直接打開https://www.baidu.com/test服務器會找不到這個頁面而報404的錯git
對此錯誤我想到了兩種解決方法github
其二是你跳轉頁面用不一樣參數的形式來跳轉頁面,如windows
原來地址是:https://www.baidu.com後端
而後點擊跳轉的時候執行
history.pushState(data, title, '?page=test')
而後瀏覽器地址欄的地址是https://www.baidu.com?page=test
而後當你訪問https://www.baidu.com?page=test頁面的時候會打開https://www.baidu.com而後你能夠根據page參數的值來判斷用戶想訪問的頁面,進行不一樣的渲染
<div id="msg"></div> <br><br> <span class="msgBtn" data-route='A'>toFirst</span> <span class="msgBtn" data-route='B'>toSecond</span> <span class="msgBtn" data-route='C'>toThird</span>
樣式很簡單就是一個顯示信息的msg而後三個按鈕對應不一樣的頁面
//路由註冊 const message = { undefined: 'massage', A: 'hahahh', B: 'hehehehe', C: 'hohohoho' }; //頁面分發加載 function showMsg(el) { const _loc = location.href; let url_msg_id = GetRequest(_loc); el.html(message[url_msg_id.msg]); } //監聽前進後退按鈕 window.addEventListener('popstate', function (e) { showMsg($('#msg')); }); //點擊切換路由 $('.msgBtn').click(function (e) { console.log(e.currentTarget ); history.pushState(null, null, '?msg=' + e.target.dataset.route); showMsg($('#msg')); }); //處理url function GetRequest() { let url = location.search; //獲取url中"?"符後的字串 let theRequest = {}; if (url.indexOf("?") !== -1) { let str = url.substr(1); let strs = str.split("&"); for (let i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } //頁面加載渲染 showMsg($('#msg'));
當你點擊toFirst會把url的msg參數變成toFirst對應的data-route,而後觸發showMsg方法,獲取到當前的url的參數在message中找到對應要渲染的字符,渲染在msg上。
效果以下
而後點擊toSecond
點擊瀏覽器的返回按鈕,經過監聽來從新調用showMsg方法,因此會回到這個頁面
若是你直接打開http://localhost:63342/history/index.html?msg=C
也會在index.html裏面進行showMsg處理來打開對應的頁面
<html> <head> <title></title> <style type="text/css"> div { margin: 10px; } .msgBtn { margin: 10px; padding: 10px; border: 1px solid black; } </style> </head> <body> <div id="msg"></div> <br><br> <span class="msgBtn" data-route='A'>toFirst</span> <span class="msgBtn" data-route='B'>toSecond</span> <span class="msgBtn" data-route='C'>toThird</span> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> <script type="text/javascript"> //路由註冊 const message = { undefined: 'massage', A: 'hahahh', B: 'hehehehe', C: 'hohohoho' }; //頁面分發加載 function showMsg(el) { const _loc = location.href; let url_msg_id = GetRequest(_loc); el.html(message[url_msg_id.msg]); } //監聽前進後退按鈕 window.addEventListener('popstate', function (e) { showMsg($('#msg')); }); //點擊切換路由 $('.msgBtn').click(function (e) { console.log(e.currentTarget ); history.pushState(null, null, '?msg=' + e.target.dataset.route); showMsg($('#msg')); }); //處理url function GetRequest() { let url = location.search; //獲取url中"?"符後的字串 let theRequest = {}; if (url.indexOf("?") !== -1) { let str = url.substr(1); let strs = str.split("&"); for (let i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } //頁面加載渲染 showMsg($('#msg')); </script> </body>
實現思路和以前的大概相同就是變化後面的哈希值,而後經過hashchange監聽到哈希值的變化
demo地址 https://github.com/WindStormrage/Single-page-application/blob/master/hash/index.html
這樣子是大概實現出了一個單頁面的效果可是,還有幾個單頁面的要素沒有體現出來,好比異步靜態文件的加載。
而後hash的缺點是,只好設置一層路由若是還有子頁面須要路由會比較麻煩,而後還有的是就是#這個字符讓url顯得很是不美觀