思路:根据路径变化展示相应的内容
Hash模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>原生实现路由Hash模式</title>
</head>
<body>
<head class="header">
<h1>我是头部</h1>
</head>
<!-- 左侧导航栏 -->
<section class="section_left">
<ul>
<li>
<a href="/">这是默认菜单</a>
</li>
<li>
<a href="#/html">HTML学习</a>
</li>
<li>
<a href="#/css">CSS学习</a>
</li>
<li>
<a href="#/javascript">Javascript学习</a>
</li>
</ul>
</section>
<!-- 右侧内容显示区域 -->
<sidebar class="sidebar_right">
<h1>我是默认内容</h1>
</sidebar>
<!-- 底部 -->
<footer class="footer">
<h1>我是底部</h1>
</footer>
<script>
(function() {
var Router = function() {
this.routes = {}; //保存路由
this.curUrl = ""; //获取当前的hash值
};
Router.prototype.init = function() {
//hashchange事件,当hash变化时,调用reloadPage方法
//第一个this指向window,bind里面的this指向调用这个函数的对象,具体使用方法可以百度
window.addEventListener("hashchange", this.reloadPage.bind(this));
};
Router.prototype.reloadPage = function() {
this.curUrl = location.hash.substring(1) || "/"; //获取当前hash的值(去掉#)
this.routes[this.curUrl](); //运行当前hsah值对应的函数
};
Router.prototype.map = function(key, callback) {
//保存路由对应的函数:
this.routes[key] = callback; //key表示hash的值(去掉#),callback表示当前hash对应的函数
};
window.oRou = Router;
})();
var oRouter2 = new oRou();
oRouter2.init();
oRouter2.map("/", function() {
var oSidebar = document.querySelector("sidebar");
oSidebar.innerHTML = "我是主页";
});
oRouter2.map("/html", function() {
var oSidebar = document.querySelector("sidebar");
oSidebar.innerHTML = "我是html页面";
});
oRouter2.map("/css", function() {
var oSidebar = document.querySelector("sidebar");
oSidebar.innerHTML = "我是css页面";
});
oRouter2.map("/javascript", function() {
var oSidebar = document.querySelector("sidebar");
oSidebar.innerHTML = "我是javascript页面";
});
</script>
<style>
* {
padding: 0;
margin: 0;
}
a {
text-decoration: none;
color: #ffffff;
}
.header {
width: 100%;
height: 100px;
background-color: rgb(198, 195, 212);
text-align: center;
line-height: 100px;
color: #865a5a;
}
.section_left {
width: 16%;
height: 500px;
float: left;
background-color: rgb(173, 145, 145);
}
.section_left ul li {
list-style: none;
width: 100%;
height: 50px;
border-bottom: 1px solid #ffffff;
text-align: center;
line-height: 50px;
}
.sidebar_right {
width: 78%;
float: right;
height: 470px;
background-color: rgb(105, 90, 90);
margin-right: 3%;
margin-top: 15px;
text-align: center;
line-height: 470px;
border-radius: 10px;
color: #e6cdcd;
}
.footer {
width: 100%;
height: 100px;
background-color: rgb(190, 195, 216);
clear: both;
text-align: center;
line-height: 100px;
color: #925959;
}
</style>
</body>
</html>
History模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>原生实现路由History模式</title>
</head>
<body>
<header class="header">
<h1>我是头部</h1>
</header>
<!-- 左侧导航栏 -->
<section class="section_left">
<ul>
<li>
<a href="javascript:;" data-href="/home">首页</a>
</li>
<li>
<a href="javascript:;" data-href="/abc">菜单一</a>
</li>
<li>
<a href="javascript:;" data-href="/def">菜单二</a>
</li>
<li>
<a href="javascript:;" data-href="/ghi">菜单三</a>
</li>
</ul>
</section>
<!-- 右侧内容显示区域 -->
<sidebar class="content">
<h1>我是默认内容</h1>
</sidebar>
<!-- 底部 -->
<footer class="footer">
<h1>我是底部</h1>
</footer>
<script>
const history = window.history;
const createSomeElement = (textContent) => {
const div = document.createElement("div");
div.textContent = textContent;
return div;
};
// 路径与路由组件的银映射
const pages = {
"/home": createSomeElement("首页"),
"/abc": createSomeElement("内容一"),
"/def": createSomeElement("内容二"),
"/ghi": createSomeElement("内容三"),
};
const IfRedirectPath = (path) => {
const pagesId = Object.keys(pages);
if (path == "/" || !pagesId.includes(path)) {
path = "/home";
history.pushState({}, "", "/home");
}
return path;
};
const renderPage = (path) => {
// redirect的逻辑
path = IfRedirectPath(path);
const cont = document.querySelector(".content");
const firstChild = cont.firstElementChild;
if (firstChild) {
cont.removeChild(firstChild);
}
cont.appendChild(pages[path]);
};
const myRouter = function() {
const handlers = [];
const listen = (listener) => {
handlers.push(listener);
// return function unlisten() {
// handlers.filter((h) => h !== listener);
// };
};
const call = (location) => {
handlers.forEach((cb) => cb(location));
};
window.addEventListener("popstate", function() {
call({ url: window.location.pathname });
});
return {
listen,
call,
};
};
const { listen, call } = myRouter();
const push = (url, state = {}, title) => {
try {
history.pushState(state, title, url);
} catch (e) {
window.assign(url);
}
call({ state, title, url });
};
document
.querySelector(".section_left")
.addEventListener("click", function(e) {
if (e.target.tagName !== "A") return;
push(e.target.dataset.href);
});
var unListen = listen(function(loc) {
renderPage(loc.url);
});
window.addEventListener("load", function() {
const path = window.location.pathname;
push(path);
});
</script>
<style>
* {
padding: 0;
margin: 0;
}
a {
text-decoration: none;
color: #ffffff;
}
.header {
width: 100%;
height: 100px;
background-color: rgb(198, 195, 212);
text-align: center;
line-height: 100px;
color: #865a5a;
}
.section_left {
width: 16%;
height: 500px;
float: left;
background-color: rgb(173, 145, 145);
}
.section_left ul li {
list-style: none;
width: 100%;
height: 50px;
border-bottom: 1px solid #ffffff;
text-align: center;
line-height: 50px;
}
.content {
width: 78%;
float: right;
height: 470px;
background-color: rgb(105, 90, 90);
margin-right: 3%;
margin-top: 15px;
text-align: center;
line-height: 470px;
border-radius: 10px;
color: #e6cdcd;
}
.footer {
width: 100%;
height: 100px;
background-color: rgb(190, 195, 216);
clear: both;
text-align: center;
line-height: 100px;
color: #925959;
}
</style>
</body>
</html>