路由是什么
分发请求的组件;
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中保存的路径加载目标页面;