js web简单的路由管理器
灵感来自此博客
主要模拟了Router的实现原理
客供大家参考
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document - JoyNopRouter</title>
</head>
<body>
<div id="root"></div>
<button class="t1">JoyNop 2hahaha</button>
<button class="t2">home</button>
<button class="t3">about</button>
<template id="home">
<h1>home</h1>
</template>
<template id="about">
<h1>about</h1>
</template>
<template id="joynop">
<h1>joynop</h1>
</template>
<template id="notFound">
<h1>404 not found</h1>
</template>
<!-- <script src="./aja-router.js"></script> -->
<script type="module">
import { JoyNopRouter } from "./joynop-router.js";
const router = new JoyNopRouter();
router.forRoot([
{
path: "",
redirectTo: "home"
},
{
path: "home",
render(host) {
const t = document.querySelector("#home");
host.append(document.importNode(t.content, true));
}
},
{
path: "about",
render(host) {
const t = document.querySelector("#about");
host.append(document.importNode(t.content, true));
}
},
{
path: "joynop/:id",
render(host, route) {
const t = document.querySelector("#joynop");
const joynop = document.importNode(t.content, true);
joynop.querySelector(
"h1"
).innerHTML = `joynop, id is ${route.params.id.value}`;
host.append(joynop);
}
},
{
path: "**",
render(host) {
const t = document.querySelector("#notFound");
host.append(document.importNode(t.content, true));
}
}
]);
document.querySelector(".t1").addEventListener("click", (e) => {
router.push("joynop/2");
});
document.querySelector(".t2").addEventListener("click", (e) => {
router.push("home");
});
document.querySelector(".t3").addEventListener("click", (e) => {
router.push("about");
});
</script>
</body>
</html>
joynop-router.js
const _textIsDynamicRouteExp = /\/?:[a-zA-Z]+/;
export class JoyNopRouter {
_host = document.querySelector("#root");
_routes = [];
constructor(host) {
if (host) this._host = host;
this._setup();
}
_setup() {
window.addEventListener("load", (e) => {
this._render();
});
window.addEventListener("popstate", (e) => {
this._render();
});
// window.addEventListener("hashchange", e => {
// console.log("hash ");
// });
}
forRoot(routes = []) {
this._routes = routes.map((route) => {
const { path } = route;
const pathSplit = path.split("/");
console.log(pathSplit);
if (path && path.match(_textIsDynamicRouteExp)) {
route.isDynamic = true;
// 动态路由
const params = {};
let exp = "";
for (var i = 0; i < pathSplit.length; i++) {
const item = pathSplit[i];
let expItem = "/" + item;
if (item.startsWith(":")) {
params[item.replace(/^:/, "")] = { index: i };
expItem = `/(?<${item.replace(/^:/, "")}>[^/]+)`;
}
exp += expItem;
}
if (exp && exp.trim() !== "") {
exp = exp.replace(/\//, "");
}
route.exp = new RegExp(exp);
route.params = params;
}
return route;
});
}
_findHashRoute(path) {
const hash = path ?? document.location.hash.replace(/#\/?/, "");
return this._match(hash);
}
/**
* 使用path在routes中寻找路由
*/
_match(path) {
// 1, 先找普通路由
let route = this._routes.find((i) => i.path === path);
if (route) {
return route;
}
// 2, 找动态路由
route = this._routes
.filter((i) => i.isDynamic)
.find((i) => {
const pattern = "/";
const routeNameSplit = path.split(pattern);
const dynamicRouteNameSplit = i.path.split(pattern);
const equalRouteLength =
routeNameSplit.length === dynamicRouteNameSplit.length;
const match = path.match(i.exp);
if (match && match.groups) {
for (const k in match.groups) {
const param = i.params[k];
param.value = match.groups[k];
}
}
return equalRouteLength && match;
});
if (route) {
return route;
}
// 3, 都没找到,默认返回404路由
return this._find404Route();
}
_find404Route() {
return this._routes.find((i) => i.path === "**");
}
_render(path) {
const matchRoute = this._findHashRoute(path);
if (matchRoute) {
this._host.innerHTML = "";
if (matchRoute.redirectTo) {
this._render(matchRoute.redirectTo);
} else {
matchRoute.render(this._host, matchRoute);
}
}
}
push(path) {
try {
this._render(path);
window.history.pushState({}, document.title, `#/${path}`);
} catch (error) {}
}
}
示例如下
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭