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.前端路由的前生今世及实现原理

相关文章
相关标签/搜索