8 Vue2 前端路由实现思路

84 阅读3分钟

路由是什么

分发请求的组件;
demo
在demo中,通过window.location.hash获取url的锚,不同div模拟不同网页。 html:

<body>
<div id="app"></div>
<div id="div1" style="display: none;">第一页</div>
<div id="div2" style="display: none;">第二页</div>
<div id="div3" style="display: none;">第三页</div>
<div id="div4" style="display: none;">第四页</div>
<div id="div5" style="display: none;">第五页</div>
<script src="src/index.js"></script>
</body>

在js中:

const number = window.location.hash.substring(1);
const div = document.querySelector(`#div${number}`);
const app = document.querySelector("#app");
div.style.display = "block";
app.appendChild(div);

此时,通过地址加上#1这样的锚,js代码读到锚,然后加载不同的页面;

如果,地址是在html中的超链呢?

<a href="#1">第1页</a>
<a href="#2">第2页</a>
<a href="#3">第3页</a>
<a href="#4">第4页</a>
<a href="#5">第5页</a>

URL标识符变化监听,锚点变化监听

// 获取路径
const number = window.location.hash.substring(1);
// 获取目标页面
const div = document.querySelector(`#div${number}`);
// 获取根页面
const app = document.querySelector(`#app`);
// 加载目标页面到根页面
if (div) div.style.display = "block";
if (app && div) app.appendChild(div);
window.addEventListener("hashchange", (v) => {
  // 获取路径
  const number2 = window.location.hash.substring(1);
  // 获取用户点击的新页面
  const div2 = document.querySelector(`#div${number2}`);
  // 获取根页面
  const app2 = document.querySelector(`#app`);
  // 设置新页面属性展示
  div2.style.display = "block";
  const node = app2.children[0]; // 备份上一个页面
  // 展示新的页面
  document.body.appendChild(node);
  node.style.display = "none"; // 上一个页面不展示
  app2.appendChild(div2); // 上一个页面
});

代码稍作优化如下:

function route() {
  const app = document.querySelector(`#app`);
  let number = window.location.hash.substring(1) || 1; // 默认路由1
  let div = document.querySelector(`#div${number}`);
  div = div || document.querySelector(`#div404`); // 保底路由
  div.style.display = "block";
  let node = app.children.length && app.children[0];
  node && document.body.appendChild(node);
  node && (node.style.display = "none");
  app && div && app.appendChild(div);
}
route();
window.addEventListener("hashchange", (v) => {
  route();
});

路由表

用路由表的形式,跳转url的目标页面,用下面的routeForTable()替换上面的route()就可以了:

const div1 = document.createElement("div");
div1.innerHTML = "第一页";
const div2 = document.createElement("div");
div2.innerHTML = "第二页";
const div3 = document.createElement("div");
div3.innerHTML = "第三页";
const div4 = document.createElement("div");
div4.innerHTML = "第四页";
const div5 = document.createElement("div");
div5.innerHTML = "第五页";
const div404 = document.createElement("div");
div404.innerHTML = "404";
const routeTable = {
  "1": div1,
  "2": div2,
  "3": div3,
  "4": div4,
  "5": div5,
  "404": div404
};
function routeForTable() {
  const app = document.querySelector(`#app`);
  let number = window.location.hash.substring(1) || 1; // 默认路由1
  let div = routeTable[number] || routeTable[404]; // 保底路由
  app.innerHTML = "";
  app && div && app.appendChild(div);
}

嵌套路由

对URL地址中得到的路径进行处理,如果是一级路径直接跳转,如果是二级路径,先根据路由表加载一级页面,然后加载二级页面;

hash路由和history路由

  • hash路由,类似https://fmpw5p.csb.app/#9936,其中#9936就是hash,任何情况下都可以用hash做前端路由,缺点是SEO不友好(浏览器是不会把#以后的内容发给服务器的)
  • history路由,直接用/9936,使用条件是,后端可以将所有前端路由都渲染同一页面,缺点是IE8以下不支持;

history模式

其中,window.location.pathname是从url中获得路径

<a class="link" href="/1">第1页</a>
<a class="link" href="/2">第2页</a>
<a class="link" href="/3">第3页</a>
<a class="link" href="/4">第4页</a>
<a class="link" href="/5">第5页</a>
const routeTableHistory = {
  "/1": div1,
  "/2": div2,
  "/3": div3,
  "/4": div4,
  "/5": div5,
  "/404": div404
};
function routeForTableSmartHistory(container) {
  let number = window.location.pathname || "/1"; // 默认路由1
  let div = routeTableHistory[number] || routeTableHistory["/404"]; // 保底路由
  app.innerHTML = "";
  container.appendChild(div);
}

这种情况下,不需要写has变化监听,window.addEventListener("hashchange",()=>{}),也能在点击超链接时跳转不同页面时,但跳转动作是一个新的请求,并不友好;

history api

1,阻止a标签的默认动作

const allA = document.querySelectorAll("a.link");
for (let a of allA) {
  a.addEventListener("click", (e) => {
    e.preventDefault();
  });
}

2,获取a标签的内容

const path = a.getAttribute("href");

3,修改a标签点击事件,history api,在不刷新数据的情况下改变URL

const allA = document.querySelectorAll("a.link");
for (let a of allA) {
  a.addEventListener("click", (e) => {
    e.preventDefault();
    const href = a.getAttribute("href");
    window.history.pushState(null, `page ${href}`, href);
    onStateChange(href);
  });
}

function onStateChange(href) {
  routeForTableSmartHistory(app);
}

memory模式的路由,这种路由对于非浏览器很有市场

1,rute()方法中,路径number不从url获取,而是从localstorage中获取

function routeForTableSmartMemory(container) {
  let number = window.localStorage.getItem("xxx") || "/1"; // 默认路由1
  let div = routeTableHistory[number] || routeTableHistory["/404"]; // 保底路由
  app.innerHTML = "";
  container.appendChild(div);
  window.localStorage.setItem("xxx", number);
}

2,在a标签点击事件中,修改localstorage中存储的路径

const allA = document.querySelectorAll("a.link");
for (let a of allA) {
  a.addEventListener("click", (e) => {
    e.preventDefault();
    const href = a.getAttribute("href");
    // onStateChange(href);
    onStateChangeMemory(href);
  });
}

function onStateChangeMemory(href) {
  window.localStorage.setItem("xxx", href);
  routeForTableSmartMemory(app);
}

vue router

官方文档

小结

hash,是浏览器监听到url中hash变化,然后进行的处理; history,拦截a标签点击事件,修改url地址,加载目标页面; memory,拦截a标签点击事件,修改localstorage中保存的路径,最后通过localstorage中保存的路径加载目标页面;