路由 VueRouter

82 阅读3分钟

路由本质

路由的本质是分发。其作用就是分发请求,把对应的请求分发到对应的位置。

image.png

原生 JS 实现路由

// index.html
<a href='#1'>go to 1</a>
<a href='#2'>go to 2</a>
<a href='#3'>go to 3</a>
<a href='#4'>go to 4</a>
<div id='app'></div>
<div id="div1" style="display:none">1</div>
<div id="div2" style="display:none">2</div>
<div id="div3" style="display:none">3</div>
<div id="div4" style="display:none">4</div>
<div id="div404" style="display:none">不存在此页面</div>
<script src="index.js"></script>
// index.js
// 获取用户想去哪里
let number = window.location.hash.substr(1);
// (默认路由)number 若存在即为 number 否则 number 为 1
number = number || 1
// 获取界面
let div = document.querySelector(`div${number}`);
let app = document.querySelector("#app");
// 渲染界面
if(div){
  div.style.display = "block";
} else{
  // 保底路由
  div = document.querySelector('div404');
  div.style.display = "block";
}
// 展示界面
app.appendChild(div)
// 当 url 变化时触发 hashchange 事件
window.addEventListener("hashchange", () => {
  const number2 = window.location.hash.substr(1);
  let div2 = document.querySelector(`div${number2}`);
  if(div2){
    div2.style.display = "block";
  } else {
    div2 = document.querySelector('div404');
    div2.style.display = "block";
  }
  const app2 = document.querySelector("#app");
  app2.children[0].style.display = "none";
  app2.appendChild(div2)
});

image.png

// 上面代码优化为 路由表
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div1.innerHTML = "2";
const div3 = document.createElement("div");
div1.innerHTML = "3";
const div4 = document.createElement("div");
div1.innerHTML = "4";
const routeTable = {
  "1":div1,
  "2":div2,
  "3":div3,
  "4":div4,
}
function route(){
  let number = window.location.hash.substr(1);
  let app = document.querySelector("#app");
  number = number || 1;
  let div = routeTable[number.toString()];
  if(!div){
    div = document.querySelector('div404');
  } 
  div.style.display = "block";
  if(app.children.length > 0){
    app.children[0].style.display = "none";
    document.body.appendChild(app.children[0]);
  }
  app.appendChild(div);
}
route();
window.addEventListener("hashchange", () => {
  route();
});

后端路由

服务器将浏览器请求的URL解析之后映射成对应的函数,这个函数根据资源类型的不同进行不同的操作,静态资源就进行文件读取,动态数据就会通过数据库进行增删改查的操作。

本质是URL请求地址与服务器资源之间的对应关系。

前端路由

由于单页面应用SPA的兴起,前端页面 = 组件化,不同的页面就是不同的组件,页面的切换就是组件的切换,页面切换不需再通过 http 请求,直接通过 JS 解析 URL 地址,然后找到对应的组件进行渲染。

与后端路由最大的不同是:不需要再经过服务器,直接在浏览器下通过 JS 解析页面之后就可以拿到相应的页面。

几种模式

模式使用场景备注
hash任何情况能做前端路由
通过 URL 的 hash 存路径
Vue-router默认路由模式
SEO不友好
history只有后端将所有前端路由都渲染同一页面
通过 URL 的 history 存路径
基于HTML5的history对象
IE8以下不支持
memory适合非浏览器,app中使用
不使用 URL
单机版路由

基于 hash 实现

基于URL地址的hash,也就是hash的变化会导致浏览器记录访问历史的变化,但是hash的变化不会触发新的URL请求。

hash值是指URL #后面的内容,通过location.hash属性可读写hash值,通过监听window对象的hashchange事件,就可以感知到hash值变化。

基于 history 实现

history提供了两个函数修改URL,监听URL变化通过监听window对象上的popstate事件来实现。两个函数不会触发popstate事件,需要手动触发页面渲染。

history.pushState()    // 新增一个历史记录
history.replaceState() // 直接替换当前的历史记录

还需要服务端设置,将所有URL请求转向前端页面,交给前端进行解析。

路由解析

vue-routerreact-router都同时依赖Path-to-RegExp这个第三方库进行路由解析。

  • 路由匹配

当获取到请求路径后,如何找到对应的配置路径

  • 路由生成 通过配置的请求路径字符串和参数生成对应的请求路径

vue-router 工作流程

url改变 => 触发事件监听 => 改变vue-router中的 current 变量 => 监视 current 变量的监视者 => 获取新的组件 => render渲染