前端路由实现常用的两种思路,history和hash

17 篇文章 1 订阅

路由的实现方式

vue可以通过vue-router实例来配置路由规则列表,指定路径path与组件component的对应关系。可以通过mode这一参数控制路由的实现模式,默认值是hash,基于hash的实现方式,如果显示设置为history,则会设为基于history API的实现方式.

面试简单回答:
1、hash: 为默认 hash 模式 ,使用 URL的hash来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

2、history : 这种模式充分利用history.pushStateAPI 来完成 URL 跳转而无须重新加载页面。

1,利用监控锚点hash的变化实现前端路由思路(location.hash+hashchange事件

参考hash.html

hash方式是通过锚点来改变浏览器的URL,体现在URL后面会加上#,并且可以通过 window.onhashChange 来监听这一变化,从而我们可以建立好hash值和对应回调函数的映射关系,然后可以通过点击a标签,实现在不刷新页面情况下,通过ajax发送请求获取异步数据来改变页面的结构。

window.addEventListener("hashchange", function(){}, false)
  • 触发hash值的变化有2种方法
    (1), 通过a标签,设置href属性,当标签点击之后,地址栏会改变,同时会触发hashchange事件
    <a href="#kaola">to KAOLA</a>

    (2), 通过js直接赋值给location.hash,也会改变url,触发hashchange事件
    location.hash="#kaola"

  • 优点

    • 无需向后端发起请求,在页面的 hash 值发生变化时,无需向后端发起请求,window.hashChange就可以监听事件的改变,并按规则加载相应的代码就好
    • 兼容性较好,大部分浏览器支持
  • 缺点

    • '#'不太美观;
    • 由于Hash对于服务端来说是不可见的,所以对于SEO不友好
2,利用History新API (pushState() 、replaceState() + popstate事件

参考history.html
HTML5中history对象,可以通过pushState() 方法或 replaceState() 方法可以修改url的地址, 并在popstate事件中能监听地址的改变,不同的是,手动的进行pushState()并不会触发popstate事件。

这两个API(pushState()和replaceState())
相同之处是都会操作浏览器的历史记录,而不会引起页面的刷新。
不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。
这两个api,加上state改变触发的popstate事件,提供了单页应用的另一种路由方式。

需要特殊处理的两种方式
  • 点击a链接
    这种方式只需要在他的onclick事件先阻止他的默认跳转行为,然后获取他的url,调用pushState/replaceState改变URL,然后根据url和回调函数的映射关系,触发相应的动作

  • 直接在脚本中调用pushState/replaceState
    点击浏览器的前进/后退按钮,这里需要用到另一个事件,onpopState, 当激活浏览器历史记录时会被触发,注意这个事件不会被pushState/replaceState触发,这个事件回调会可以获取到当前路由下我们之前通过pushState/replaceState存入的信息,也可以拿到url信息,然后根据映射关系去执行回调。

history 扩展

  • 后退一个记录window.history.back() 前进一个记录window.history.forward()
  • 跳转第n次记录 window.history.go(n) 。 window.history.go(-1) 相等于window.history.back(),
  • window.history.go(1) 相等于 window.history.forward(), window.history.go(0) 相等于 刷新
  • pushState() 用于向history对象添加当前页面的记录,并且改变浏览器地址栏的URL。
  • onpopstate事件,该事件在窗口历史记录改变时被触发。

两种方式的对比

基于Hash的路由,兼容性更好;
基于History API的路由,则更正式,可以设置与当前URL同源的任意URL,路径更直观。
另外,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造,配置不同的路由都返回相同的页面。

调用 history.pushState() 比使用 hash 存在的优势

  • pushState 设置的 url 可以是同源下的任意 url ;而 hash 只能修改 # 后面的部分,因此只能设置当前 url 同文档的url
  • pushState 设置的新的 url 可以与当前 url 一样,这样也会把记录添加到栈中;hash设置的新值不能与原来的一样,一样的值不会触发动作
  • pushState 通过 stateObject参数可以将任何数据类型添加到记录中;hash 只能添加短字符串
  • pushState 可以设置额外的 title 属性供后续使用

劣势:

  • history 在刷新页面时,如果服务器中没有相应的响应或资源,就会出现404。因此,如果 URL 匹配不到任何静态资源,则应该返回同一个
  • index.html 页面,这个页面就是你 app 依赖的页面 hash 模式下,仅 # 之前的内容包含在 http请求中,对后端来说,即使没有对路由做到全面覆盖,也不会报 404

路由匹配规则

路由的匹配规则是按照书写的顺序执行的,第一条匹配成功则不去匹配下一条,利用这一特性,可以在所有匹配路由的下面拦截其它所有路由:

//创建路由对象并配置路由规则
let router = new VueRouter({
    routes:[
       {path:'/',redirect:{name:"home"}},  // 重定向到主页
       {name:'home',path:'/home',component:Home},
       {name:'login',path:'/login',component:Login},
       {path:'*',component:NotFound},    // 全不匹配的情况下,匹配NotFound组件
    ]
});

参考代码

hash.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <header>
         <a href="#/">首页</a>
         <a href="#/friend">朋友圈</a>
         <a href="#/my">个人中心</a>
    </header>
    <div id="content">
        
    </div>
</body>
<script>
    window.onload = function(){
        updateContent() 
    }

    let contentObj = document.querySelector('#content')
    window.addEventListener('hashchange',function(){
       updateContent()      
    })

    function updateContent(){
       let hash = window.location.hash;
       console.log(hash);
       if(hash === '#/'){
           contentObj.innerHTML = '首页'
       }else if(hash === '#/friend'){
           contentObj.innerHTML = '朋友圈'
       }else if(hash === '#/my'){
           contentObj.innerHTML = '个人中心'
       }  
    }
</script>
</html>

history.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>前端路由实现</title>
</head>

<body>
    <div>
        <div class="nav">
           <a href="javascript:void(0)" data-path="index">首页</a>
           <a href="javascript:void(0)" data-path="news">新闻</a>
           <a href="javascript:void(0)" data-path="about">关于</a>
        </div>
        <div id="router">
            <!-- 内容加载区域 -->
        </div>
    </div>

    <script>
        (function () {
            history.replaceState(null, null, ''); //最开始的状态,采用replace直接替换
            document.querySelector('#router').innerHTML = '<p>首页</p>'
            
            var allLinks = document.getElementsByTagName('a');
            var urlArr = window.location.href.split('?');
            var currentRouter = urlArr[urlArr.length - 1]
            currentRouter  = currentRouter ? currentRouter : 'index';
            for(var i=0;i<allLinks.length;i++){
                var allLinkItem = allLinks[i];
                var path = allLinkItem.getAttribute('data-path');
                allLinkItem.addEventListener('click', function () {
                    var text = this.text;
                    document.querySelector('#router').innerHTML = '<p>' + text + '</p>';
                    var url = this.getAttribute('data-path');
                    history.pushState(null, null, '?' + url);
                    // window.location.href = "http://localhost:3000/history.html?"+url;
                })
                if(path === currentRouter){
                    allLinkItem.click();
                }
            }

        })()
    </script>

</body>

</html>

Vue-router 跳转和 location.href 有什么区别

  • 跳转是否刷新页面
    使用 location.href= /url 来跳转,刷新了页面;
    使用 history.pushState( /url ) ,无刷新页面,静态跳转;

  • router跳转的优势
    通过 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。
    其实使用 router.push() 跳转和使用 history.pushState() 没什么差别的,因为 vue-router 就是用了 history.pushState() 。

参考链接 https://blog.csdn.net/u014298440/article/details/87467056

作者:Aniugel
链接:https://www.jianshu.com/p/4db4b191de06
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值