前端路由的实现原理(包括Angular、vue等框架)

本文介绍了前端路由的实现原理,重点讨论了Hash路由与HTML5 History API。Hash路由常用于Angular、vue等框架,利用#符号避免页面刷新,通过hashchange事件监听变化。HTML5 History API包括pushState和replaceState方法,用于无刷新更新页面,配合onpopstate事件处理历史记录。虽然History API有良好的用户体验,但需考虑浏览器兼容性问题。
摘要由CSDN通过智能技术生成

浏览器路由的介绍

通常来说路由即是URL到函数的映射,比如我们在客户端输入一个URL,该URL会被提交到一个控制器,相应的控制器会对客户端提交上来的路由进行解析, 从而找到处理这个 URL 的类和函数,然后执行。最初web系统的路由都是由服务端来实现的,后来随着前端技术的发展,web系统的路由慢慢都交由前端来实现。

hash路由

我们经常会看到有些URL带有#,这里的#一般分为两种,比如我们可以通过在路由末尾加#来使浏览器页面回到顶部,或者我们在Angular官网(https://angular.cn/tutorial/toh-pt0)上看到的,点击右边的标签来使页面滚动到对应的位置,这是根据#后面的字符串来匹配的,它会使当前页面定位到与之对应id的html标签,若#后面为空即返回顶部,这种我便称之为锚点,还有另外一种路由的方式,我们称之为 hash,hash路由在现在很多流行的主流前端框架使用非常广泛,例如Angular,angular.js,vue等等。
hash路由的实现原理主要是因为路由中hash值的改变,并不会造成浏览器的刷新,并且我们还可以通过hashchange事件来捕获hash值的改变从而来执行对应函数来从服务端获取数据,使页面能够无刷新更新。下面是一段代码示例

window.onhashchange=function(){
var currentHash = location.hash;//当前路由的hash值
var oDiv = $("body");
oDiv.innerHTML='<div>...</div>';//hash路由的改变而改变页面展示
$.ajax({
});//可以通过ajax来获取服务端数据
} 

使用hash路由还有一个好处是它能兼容一些低版本的浏览器。
像angular1.x默认使用的就是hash路由,它会对哈希、模版、处理器进行关联,例如下面是angular1.x代码

app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
 $routeProvider
 .when('/project', {
   templateUrl: '/project.html',
   controller: 'ProjectController'
 }).otherwise({
   redirectTo: '/index'
 });
}])

我们可以试试用原生的js来实现类似angular1.x的路由,代码如下:

 //路由构造器       
    function Router() {
        //接受所有的配置路由内容:锚 和 函数方法           
        this.routes = {};            //接受 改变后的 hash值           
        this.curUrl = '';            //将定义的所有路由和函数方法 传给 routes            
        this.route = function (path, callback) {
            this.routes[path] = callback || function () { };
            console.log('routes[path]:' + this.routes[path] )
        };            //hash 值改变时触发的 函数方法            
        this.refresh = function () {
            //获取改变的hash值(url中锚 # 号后面的文本)                
            this.curUrl = location.hash.slice(1) || '/';
            this.routes[this.curUrl]();
            console.log('location.hash:' + location.hash);
            console.log('curUrl:' + this.curUrl);
            console.log('this.routes[this.curUrl]:' + this.routes[this.curUrl])
        };            //监听load(加载url)、hashchange(hash改变)事件            
        this.init = function () {
            window.addEventListener('load', this.refresh.bind(this), false);
            window.addEventListener('hashchange', this.refresh.bind(this), false)
        }
    }
    var R = new Router();//使用Router构造器         
    R.init();//监听时间         
    var res = document.getElementById('body');//我们暂时获取body,用以更新body中的页面  
    //定义所有需要用的 路由:hash值 和 加载的内容        
    R.route('/', function () {
        res.style.background = 'blue';
        res.innerHTML = '<div>...</div>';
    })
    R.route('/index', function () {
        res.style.background = 'orange';
        res.innerHTML = '<div>...</div>';
    })
    R.route('/project', function () {
        res.style.background = 'black';
        res.innerHTML = '<div>...</div>';
    })

HTML5 History API

History API是近年最新提出的概念,他包括2个方法:history.pushState()和history.replaceState(),和1个事件:window.onpopstate。
其中history.pushState()和history.replaceState()都能接收三个参数,分别是

1)状态对象(state object) — 它会和同时作为参数的url会关联在一起,我们可以将它理解为一个用来存储自定义数据的元素。无论何时我们导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。

2)标题(title) —一个字符串,目前大多数浏览器都会忽略它(不排除以后会使用,作为页面标题),建议设置为空字符串。

3)地址(URL) — 一条新的历史记录条目的地址(该参数是可选的)。新的URL可能是绝对路径,也可能是相对路径,如果是相对路径,就会自动以当前URL为基准;但是需要注意的是我们传入的URL应与当前URL同源,否则,pushState()会抛出异常。
以上我们可以看出replaceState跟pushState大致相同,唯一的不同之处就是replaceState会替换当前的历史记录,而pushState会在尾部添加一条新的历史记录,这与replace跟push的字面意思相符。
当然我们必须得亲测一下了,首先我打开chrom进入百度然后在控制台输入window.history得到如下信息:
在这里插入图片描述
首先我们先测试下pushState,我们继续在控制台输入window.history.pushState(“myState”,null,“https://www.baidu.com/mystate”)
现在浏览器的网址就变成了如下所示,但是页面并没有刷新。
在这里插入图片描述
这时候我们再看看window.history的信息:
在这里插入图片描述
我们可以发现history中新增了一条记录,从其中的length属性从2变成了3可以看出,而且我们发现其中State属性不在是null,而是我们刚才设置的myState。
接下来我们在测试下replaceState,这次我们输入window.history.replaceState(“replace”,null,“https://www.baidu.com/myreplace”)
这次浏览器网址同样发生了改变如下所示,但是页面同样也没刷新。
在这里插入图片描述
同样我们也要看看这时候history中的信息,
在这里插入图片描述
我们可以发现这时候history中并没有新增一条记录,length属性仍然为3,但是State属性变成了"repalce",我们还可以试试window.history.back()的方法,我们可以发现回到是https://www.baidu.com/,并没有回到之前的https://www.baidu.com/mystate,这是由于当前的记录已经被替换了。另外还需要值得注意的一点是pushState跟replaceState中的url都不支持跨域,否则会报错。
接下来我们来了解下window.onpopstate事件,从字面意思我们可以发现push是添加,pop是拿出,他们是相对的,自然不难理解这个事件是取出浏览器中的历史记录加载时触发的,但是这个事件要求还是比较严苛的,只有在点击浏览器前进、后退按钮或者是js调用window.history中的back(),go()等方法时才触发,那么假设页面刷新时,这个事件肯定就不会触发了,这个事件被设计出来的初衷应该就是跟pushState和replaceState一起搭配使用的,但是值得注意的是调用pushState和replaceState时也并不会触发window.onpopstate事件哦。接下来我们来看看如何使用这个window.onpopstate事件,先看代码:

// 例如当前的url为:http://test.com/first.html
window.onpopstate=function()
{
    // 获得存储在该历史记录中当前的state对象
    var myState=window.history.state;
    // 我们可以通过不同的myState来加载不同页面
}
//下面是jquery的方法,jQuery对event做了一层包装
$(window).on("popstate", function(event) {
   //我们需要通过originalEvent取得原生event。
    var state = event.originalEvent.state,
        // 本示例直接取URL参数来处理
        reg = /page=(\d+)/,
        regMatch = reg.exec(location.search),
        // 假设第1页的时候是 ?page=1
        newPage= regMatch === null ? 1 : +regMatch[1];
    updatePage(newPage);//加载当前页面
});

All in all 我们可以发现HTML5 History API使用起来还是非常简单的,它的缺陷可能就在于它的兼容性吧

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值