天天看点

怎样理解Vue中的路由

1. 路由

  • 传统的路由指的是:当用户访问一个

    url

    时,对应的服务器会接收这个请求,然后解析url中的路径,从而执行对应的处理逻辑。这样就完成了一次路由分发。
  • 而前端路由是不涉及服务器的,是前端利用

    hash

    或者

    HTML5

    history API

    来实现的,一般用于不同内容的展示和切换。

目前

Vue

推荐单页面应用

SPA

开发模式,大型单页应用最显著特点之一就是采用前端路由系统,通过改变

URL

,在不重新请求页面的情况下,更新页面视图。

Vue

中的路由解决方案为

vue-router

它提供两种不同方式的路由方式:

Hash

History

,在

vue-router

中是使用了外观模式将几种不同的路由方式提供了一个一致的高层接口,让我们可以更解耦的在不同路由方式中切换。

Hash

History

除了外观上的不同之外,还有一个区别是:

Hash

方式的状态保存需要另行传递,而

HTML5 History

原生提供了自定义状态传递的能力,我们可以直接利用其来传递信息。

vue-router

中是通过

mode

这一参数控制路由的实现模式的:

怎样理解Vue中的路由

2. Hash

Hash

方法是在路由中带有一个

#

,主要原理是通过监听

#

后的

URL

路径标识符的更改而触发的浏览器

hashchange

事件,然后通过获取

location.hash

得到当前的路径标识符,再进行一些路由跳转的操作,参见 MDN:

  • location.href

    :返回完整的

    URL

  • location.hash

    :返回

    URL

    的锚部分;
  • location.pathname

    :返回

    URL

    路径名;
  • hashchange

    事件:当

    location.hash

    发生改变时,将触发这个事件。

比如访问一个路径

http://sherlocked93.club/base/#/page1

,那么上面几个值分别为:

# http://sherlocked93.club/base/#/page1
{
  "href": "http://sherlocked93.club/base/#/page1",
  "pathname": "/base/",
  "hash": "#/page1"
}
           

看一个例子:

<html>
<head>
  <style>
    li {
      cursor: pointer;
    }
  </style>
</head>
<body>
<div id="main">
  <p>router-hash</p>
  <ul id="list">
    <li><a href="#router1" target="_blank" rel="external nofollow" >router1</a></li>
    <li><a href="#router2" target="_blank" rel="external nofollow" >router2</a></li>
    <li><a href="#router3" target="_blank" rel="external nofollow" >router3</a></li>
  </ul>
  <div id="panel"></div>
</div>

<script>
  window.onload = function () {
    window.onhashchange = function (opt) {
      console.log('hash has changed to: ', location.hash)
    }
  }
</script>
</body>
</html>
           

效果:

怎样理解Vue中的路由

当我们点击后退时,可见路由跳转回

router2

中。并且当我们刷新页面时不会报出

404

的错误,那是因为

hash

虽然出现在

URL

中,但不会被包括在

HTTP

请求中。它是用来指导浏览器动作的,对服务器端完全无用。

3. History API

HTML5

History API

为浏览器的全局

history

对象增加的扩展方法。一般用来解决

ajax

请求无法通过回退按钮回到请求前状态的问题。

HTML4

原有的和

HTML5

新提出的

history

的API有:

  • history.forward()

    ; //在历史记录中前进一步
  • history.back()

    ; //在历史记录中后退一步
  • history.go(n)

    : //在历史记录中跳转n步骤,n=0为刷新本页,n=-1为后退一页。
  • history.pushState(data, title, url);

    //向历史记录中追加一条记录
  • history.replaceState(data, title, url);

    //替换当前页在历史记录中的信息
  • history.state;

    //是一个属性,可以得到当前页的

    state

    信息。
  • window.onpopstate;

    //是一个事件,在点击浏览器后退按钮或

    js

    调用

    forward()

    back()

    go()

    时触发。监听函数中可传入一个

    event

    对象,

    event.state

    即为通过

    pushState()

    replaceState()

    方法传入的

    data

    参数。

以一个例子实现一下:

<html>
<head>
  <style>
    li {
      cursor: pointer;
    }
  </style>
</head>
<body>
<div id="main">
  <p>vue-router</p>
  <ul id="list">
    <li>router1</li>
    <li>router2</li>
    <li>router3</li>
  </ul>
  <div id="panel"></div>
</div>

<script>
  window.onload = function () {
    window.onpopstate = function (event) {
      console.log(event)
    };

    document.querySelector('#list').addEventListener('click', function (event) {
      if(event.target.nodeName.toLowerCase()==="li") {
        var content = event.target.innerHTML;
        var _newState;
        _newState = {
          url: location.origin + '/' + content,
          title: document.title,
          state: content
        };

        window.history.pushState(_newState, '', '/' + content);
        console.log('you have change the router to: ', content);
      }
    })
  }
</script>
</body>
</html>
           

效果:

怎样理解Vue中的路由

总而言之就是当浏览器访问一个页面时,当前地址的状态信息会被压入历史栈,当调用

history.pushState()

方法向历史栈中压入一个新的

state

后,历史栈顶部的指针是指向新的

state

的。可以将其作用简单理解为假装已经修改了

url

地址并进行了跳转 ,除非用户点击了浏览器的前进、回退,或是显式调用

HTML4

中的操作历史栈的方法,否则不会触发全局的

popstate

事件。以上例子中点击后退可见由当前的

router2

跳转到

router3

,控制台打印出

popstate

事件信息。

当我们刷新页面的时候,会报出

404

的错误:

怎样理解Vue中的路由

这也是

history

不同于

hash

的一个地方,是因为

history

模式则会将

URL

修改得就和正常向后端发起请求一样,如果后端没有配置对应的路由处理,则会返回

404

错误。

官方推荐的解决办法是在服务端增加一个覆盖所有情况的候选资源:如果

URL

匹配不到任何静态资源,则应该返回同一个

index.html

页面,这个页面就是你

app

依赖的页面。

参考:

https://www.cnblogs.com/dashnowords/p/9671213.html 大史不说话

https://juejin.im/post/5c52da9ee51d45221f242804 SHERlocked93