Web開發中路由實現原理html
什麼是路由:前端
根據不一樣的url地址,展現不一樣的頁面或者更新頁面局部視圖
Demogit
服務器端路由管理,常見的開發模式是前端根據url的不一樣,使用ajax發起異步請求,獲取不一樣的頁面資源,前端獲取資源後更新頁面。github
後端路由處理,通常是基於先後端沒有分離的項目,html和數據綁定發生在後端(後端渲染),有利於SEO,由於每次發送請求都須要獲取資源,對服務器形成資源浪費,前端頁面可能由於網速形成延遲,頁面局部視圖更新,ajax請求不一樣保存當前的請求狀態,不能使用瀏覽器前進後退快捷鍵操做。web
server路由處理實現相似於下面實現:不一樣的url請求路徑,返回不一樣的模板ajax
app.get('', function (req, res) { res.header('Access-Control-Allow-Origin', '*'); res.sendFile( __dirname + "/" + "index.html" ); }) app.get('/home.html', function (req, res) { res.header('Access-Control-Allow-Origin', '*'); res.sendFile( __dirname + "/" + "pages/home.html" ); }) app.get('*', function (req, res) { res.header('Access-Control-Allow-Origin', '*'); res.sendFile( __dirname + "/" + "pages/404.html" ); })
Demosegmentfault
在單頁面(SPA)開發中,經過Hash能夠實現前端路由,hash路由形如:http:localhost:8100/#/home,
在url後綴存在#(錨點),用來作頁面定位,即根據頁面id將該元素所在的區域展現在可視區域,#後面內容的改變不會發送請求到服務器。後端
前端路由須要實現一下:瀏覽器
原理:
頁面hash值能夠經過 window.location.hash 屬性獲取,當url的hash值發生變化,會觸發window對象的hashchange事件,經過監聽 hashchange 事件,操做 window.location.hash 屬性能夠實現服務器
Route.js
function Route(params) { if(!params){ console.log("請檢查初始化數據") return false; } this.registeredRoute = []; this.contentId = params.contentId; this.routes = params.routes; this.devStatus = params.devStatus || 'none' this.otherRouter = params.otherRouter; this.init(); } Route.prototype = { constructor: Route, init: function() { window.addEventListener('hashchange', (function(event){ var currentHash = location.hash.substring(1) || this.otherRouter; var route = this.routes && this.routes.find(item => item['path'] === currentHash); if(this.devStatus === 'log') { console.log("hash has been changed to:", currentHash) } if(route) { this.activeRoute(); this.render(route) } }).bind(this)) var initEvent = new Event('hashchange'); window.dispatchEvent(initEvent); }, //更新視圖 render(route) { if(!$){ console.log("請確保項目正確引入jQuery") return false; } var _routeContent = $(`#${this.contentId}`); if(_routeContent) { var currentView = `<div>current page: ${route['path']}</div> <div>Params:${JSON.stringify(route['params'])} </div> <div>View:${route['component']}</div>`; _routeContent.html(currentView) }else { console.log("請綁定須要更新的視圖區域"); } }, //當前激活路由樣式 activeRoute() { var _routeList = $(".route") || []; for(var i=0; i< _routeList.length;i++) { var _item = _routeList[i]; var _classList = _item.classList; var _defActice = !location.hash && _aDome['context'].getAttribute('data-route-param')==='home'); var _aDome = $(_item.getElementsByTagName("a") && $(_item.getElementsByTagName("a")[0]); var _activeBool = _aDome['context'].getAttribute('data-route-param') === location.hash.substring(1) || _defActice; if(_activeBool) { _classList.add('active') } else { _classList.remove('active'); } } } }
index.html 片斷
<div id="route-content"></div> <script> window.onload = function(){ //路由列表 var routes = [ { path:'home', params: { id:1 }, component: '<dev>home page </dev>' }, { path:'list', params: { id:2 }, component: '<dev>list page </dev>' }, { path:'about', params: { id:3 }, component: '<dev>about page </dev>' }, { path:'info', params: { id:4 }, component: '<dev>info page </dev>' } ]; var _routeContent = $("#route-content"); if(!_routeContent) { console.log("請檢查是否存在#route-content視圖區域") } var route = new Route({ contentId: 'route-content', routes: routes, //路由集合 otherRouter: 'home',//默認路由 devStatus: 'log' //設置開發模式 }); } </script>
window.history (window是瀏覽器的全局對象,因此window.history和history相同)是瀏覽器提供的用來記錄和操做瀏覽器頁面歷史棧的對象的接口,提供了經常使用的屬性和方法:
history.back(); //回退 history.go(-1); //等同於history.back(); history.forward(); //前進 history.go(1); //等同forward() window.history.length; //歷史棧頁面的數量
H5對History進行了擴展,增長了兩個重要的新的方法:
History.pushState() //瀏覽器歷史記錄壓棧,增長一條歷史記錄 History.replaceState() //瀏覽器歷史記錄最後一條數據更新,替換當前歷史記錄
操做pushState和replaceState方法會觸發popstate事件,頁面刷新不一樣瀏覽器事件監聽存在差別,Chrome和Safari會觸發popstate事件,Firefox不會觸發。
咱們能夠經過pushState(),replaceState()記錄和更新當前url和參數;
pushState(),replaceState()包含三個參數:
state:存儲當前參數的JSON title:短標題,瀏覽器實現不統一有些fireFox會直接忽略,能夠設置爲null作佔位, url:當前url,更新瀏覽器url的值