Router 路由的 hash 模式和 history 模式实现

1,479 阅读4分钟

Vue-Router 有两种模式:hash 模式和 history 模式。默认的路由模式是 hash 模式。

hash路由原理

简介: hash 模式是开发中默认的模式,它的URL 带着一个#,例如:www.abc.com/#/vue,它的 hash 值就是#/vue。

特点:hash 值会出现在 URL 里面,但是不会出现在HTTP 请求中,对后端完全没有影响。所以改变 hash 值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的 IE 浏览器也支持这种模式。hash路由被称为是前端路由,已经成为 SPA(单页面应用)的标配。

原理: hash 模式的主要原理就是 onhashchange()事件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button onclick="handleClick('#/home')">/home</button>
    <button onclick="handleClick('#/user')">/user</button>
    <div id="content"></div>
    <script>
        //监听 hashchange
        window.addEventListener("hashchange", (e) => {
            console.log(e);
            let hash = e.newURL.split('#')[1]
            const content = document.getElementById('content')
            switch(hash){
                case '/home': content.innerHTML='主页';
                break;
                case '/user': content.innerHTML='用户';
                break;
                default: break
            }
        })
        function handleClick(type){
            location.hash = type
        }
    </script>
</body>
</html>

使用 onhashchange()事件的好处就是,在页面的hash 值发生变化时,无需向后端发起请求,window 就可以监听事件的改变,并按规则加载相应的代码。除此之外,hash 值变化对应的URL 都会被浏览器记 59 录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的 hash 值和对应的URL 关联起来了。

history路由原理

简介: history 模式的 URL 中没有#,它使用的是传统的路由分发模式,即用户在输入一个 URL 时,服务器会接收这个请求,并解析这个URL,然后做出相应的逻辑处理。

特 点 : 当 使 用 history 模 式 时,URL 就像这样:abc.com/user/id。相比 hash 模式更加好看。但是,history模式需要后台配置支持。如果后台没有正确配置,访问时会返回404。API: history api 可以分为两大部分,切换历史状态和修改历史状态:

修 改 历 史 状 态 : 包 括 了 HTML5 History Interface 中新增的pushState() 和 replaceState() 方法,这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了 url,但浏览器不会立即向后端发送请求。如果要做到改变 url 但又不刷新页面的效果,就需要前端用上这两个API。切换历史状态: 包括 forward()、back()、go()三个方法,对应浏览器的前进,后退,跳转操作。 虽然 history 模式丢弃了丑陋的#。但是,它也有自己的缺点,就是在刷新页面的时候,如果没有相应的路由或资源,就会刷出404来。如果想要切换到 history 模式,就要进行以下配置(后端也要进行配置):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button onclick="handleClick('/home')">/home</button>
    <button onclick="handleClick('/user')">/user</button>
    <div id="content"></div>
    <script>
        //重写 pushState 方法
        let oldPushState = history.pushState
        // history.replaceState
        history.pushState = function (data, title, url) {
            oldPushState.call(this, data, title, url)
            const content = document.getElementById('content')
            switch(url){
                case '/home': content.innerHTML='主页'
                break;
                case '/user': content.innerHTML='用户'
                break;
                default: break
            }
        }
        function handleClick(type){
            // history.replaceState
            history.pushState({},'',type)
        }
    </script>
</body>
</html>

ng配置history模式

#配置history模式
location / {
    index  index.html; 
    try_files $uri $uri/ /index.html; 
}

两种模式对比

调用 history.pushState() 相比于直接修改hash,存在以下优势:

pushState() 设置的新 URL 可以是与当前URL 同源的任意URL;而hash 只可修改 # 后面的部分,因此只能设置与当前URL 同文档的URL;

pushState() 设置的新 URL 可以与当前URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;

pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串; pushState() 可额外设置 title 属性供后续使用。

hash 模式下,仅 hash 符号之前的 url 会被包含在请求中,后端如果没有做到对路由的全覆盖,也不会返回404 错误;history 模式下,前端的 url 必须和实际向后端发起请求的url 一致,如果没有对用的路由处理,将返回 404 错误。

hash 模式和 history 模式都有各自的优势和缺陷,还是要根据实际情况选择性的使用。

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

使用 location.href= /url 来跳转,简单方便,但是刷新了页面;

使用 history.pushState( /url ) ,无刷新页面,静态跳转;

引进 router ,然后使用 router.push( /url ) 来跳转,使用了diff算法,实现了按需加载,减少了 dom 的消耗。其实使用router跳转和使用 history.pushState() 没什么差别的,因为vue-router就是用了 history.pushState() ,尤其是在history 模式下。