深入理解前端路由

512 阅读5分钟

什么是路由

维基百科对路由的说法是

路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。 路由引导分组转送,经过一些中间的节点后,到它们最后的目的地

概念看起来很模糊,但是用大白话说:就是用户通过某种输入(选择)等途径分发请求,这就是路由。

前端路由的由来

传统的后端路由的特点是通过url发送请求给后端服务器,然后通过服务器返回的代码渲染页面。但是这样的形式缺点也很明显,就是服务器压力较大,并且整体渲染效果受网络等因素影响,体验较差。

AJAX的出现给前端带来了生机,前端也引申出SPA的单页面应用概念。而通过前端路由来向用户展示出不同的页面,这样页面就会更加流畅,大大提高用户的体验。

前端路由基本概念

前端路由实际上就是在一个html下通过修改某样东西来给用户看到不同的内容界面。

那么这个东西是什么呢?目前的解决方案是localstorageurl,通过他们来和渲染的界面形成对应关系。

SPA

SPA 是 single page web application 的简称,译为单页Web应用。 简单来说,它就是不会进行多页面跳转,而是在单一的页面内,通过获取用户的输入,得知其希望进入的内容,然后在单页面内分别展示对应的页面内容。

传统页面与SPA的区别

传统页面实际上就是我建n个HTML文件,来达到不同页面效果的跳转,这样对用户来说,不同的界面就意味着进入了不同的HTML文件。

SPA界面就是我只建一个HTML文件,把所有不同的界面都塞到这个文件中,当用户选择时,我就把对应的内容展示给他看。 上面的代码,将视图1跟视图2都写入div中,放入container里,然后通过前端路由将它渲染出来

案例模拟

hash模式

比如www.baidu.com/#1 这个#1就是hash值

hash模式就是url上面使用#来告诉浏览器,用户需要看哪个页面。因为url的#后面不会发送给服务器,而且hash事件的改变可以引发hashchange事件,所以拿来做前端路由非常方便。

     <a href="#1">to id1</a>
    <a href="#2">to id2</a>
    <div class="container">
      <div id="id1">id1</div>
      <div id="id2">id2</div>
      <div id="id404">您的页面不存在</div>
    </div>

上面的代码我定义了不同的a标签,当点击不同的a标签时,页面会改变hash值。

//父元素
let parent = document.querySelector(`.container`);
//路由表,存了用户想进入的各种界面
const routesTable = {
  "#1": document.querySelector(`#id1`),
  "#2": document.querySelector(`#id2`)
};
//render函数用来获取hash值,设置默认路由,渲染界面
function render() {
  let hash = window.location.hash; //拿到#1 #2内容
  if (!hash) {
    hash = "#1"; //默认路由
  }
  for (let child of parent.children) {
    child.style.display = "none";
  }
  if (!routesTable[hash]) {
    //保底路由
    let div = document.querySelector("#id404");
    div.style.display = "block";
  } else {
    routesTable[hash].style.display = "block";
  }
}
render();
window.addEventListener("hashchange", () => {
  //hashchange事件
  render();
});

上面的js代码就是hash模式下的代码,使用url的#来对应render函数,渲染页面。并且设置了保底路由跟404路由。

hash模式的缺点是由于#后面的内容不能发送给服务器,所以SEO并不友好。

history

history其实就是摈弃了#这样的方式,你可以直接使用路径/来对应界面,我们需要在这种模式下解决两个问题:

  • 需要监控到url栏/修改
  • 让页面不要自动刷新

解决方法: 在history api中,新增了history.pushStatehistory.replaceState两个api,它可以对url的地址进行修改并且不会刷新页面,这样也可以模拟hash模式的url跳转,但是它并不会引起hashchange事件。所以我们要修改一下上面的代码。

    <a href="/1">to id1</a>/*这里改了*/
    <a href="/2">to id2</a>
    <div class="container">
      <div id="id1">id1</div>
      <div id="id2">id2</div>
      <div id="id404">您的页面不存在</div>
    </div>
    <script src="index.js"></script>
//父元素
let parent = document.querySelector(`.container`);
//路由表,存了用户想进入的各种界面
const routesTable = {
  //路由表换成‘/’的的形式
  "/1": document.querySelector(`#id1`),
  "/2": document.querySelector(`#id2`)
};
//render函数用来获取hash值,设置默认路由,渲染界面
function render() {
  let hash = window.location.pathname; //拿到/1 /2
  if (hash === "/") {
    hash = "/1"; //默认路由
  }
  for (let child of parent.children) {
    child.style.display = "none";
  }
  if (!routesTable[hash]) {
    //保底路由
    let div = document.querySelector("#id404");
    div.style.display = "block";
  } else {
    routesTable[hash].style.display = "block";
  }
}
render();
let allA = document.querySelectorAll("a");
for (let a of allA) {
  //绑定a的所有点击事件
  a.addEventListener("click", (e) => {
    e.preventDefault();//不跳转页面 不刷新
    //此时将页面的url修改掉
    window.history.pushState(null, "", a.getAttribute("href"));
    render();
  });

history由于是根据/路径符来操作的,所以就需要后端将内容页面都渲染到单个的页面。

这种方法弥补了hash模式SEO不足的情况,缺点是ie8以下不支持(谁在乎啊?)

memory

这种方式实际上用的就是localstorage替代url栏来存放数据,我们只需要将数据保存进localstorage,需要使用时拿出来用就可以了

...//由于跟history的代码一致只修改了三行代码,就将相同的代码用...表示
//路由表,存了用户想进入的各种界面
const routesTable = {
 ...
};
//render函数用来获取hash值,设置默认路由,渲染界面
function render() {
  let hash = window.localStorage.getItem("xx");
  if (!hash) {
    hash = "/1"; //默认路由
  }
 ...
}
...
for (let a of allA) {
 ...
    window.localStorage.setItem("xx", a.getAttribute("href"));
    ...
  });
}

memory模式适合只有一个路径、或者非浏览器(比如app)的情况。

缺点是由于使用的是存储在本机上的数据,如果想要分享页面,那么会给新用户展示默认页面。

参考连接

juejin.cn/post/684490… developer.mozilla.org/zh-CN/docs/…