Web開發中路由實現原理

Web開發中路由實現原理

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" );
})

預覽

Hash路由

Demosegmentfault

在單頁面(SPA)開發中,經過Hash能夠實現前端路由,hash路由形如:http:localhost:8100/#/home,
在url後綴存在#(錨點),用來作頁面定位,即根據頁面id將該元素所在的區域展現在可視區域,#後面內容的改變不會發送請求到服務器。後端

前端路由須要實現一下:瀏覽器

  1. 根據不一樣的hash展現對應的頁面
  2. 監聽hash值的改變
  3. 保存當前url的請求狀態或者參數(好比頁面刷新和分享連接,別人能夠獲取一樣的內容)
  4. 能夠實現瀏覽器的前進後退功能

原理:
頁面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>

預覽

History

Demo

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的值

前端路由實現比較

  1. hash 路由實現: 兼容性比較好,url比較醜陋,不能使用瀏覽器棧操做前進後退
  2. History 路由實現: 比較直觀,須要服務器端配合,用戶體驗好,響應快,不須要每次發送服務器請求,經過操做瀏覽器歷史棧完成頁面跳轉,低版本瀏覽器不支持H5特性,建議使用Hash

參考:

1.前端路由的前生今世及實現原理

相關文章
相關標籤/搜索