History 路由
一、认识
History
模式 采用 HTML5
的新特性, 且提供了两个新方法: pushState()
, replaceState()
可以对浏览器历史记录栈进行修改,以及 popState
事件的监听到状态变更。pushState
方法、replaceState
方法,只能导致history
对象发生变化,从而改变当前地址栏的 URL
,但浏览器不会向后端发送请求,也不会触发popstate
事件的执行。popstate
事件的执行是在点击浏览器的前进后退按钮的时候,才会被触发
二、思路
-
通过
pushState
和replaceState
两个API
来操作实现URL
的变化。 -
可以通过
popstate
事件来监听URL
的变化,从而对页面进行跳转(渲染) -
history.pushState()
或history.replaceState()
不会触发popstate
事件, 需要手动触发页面跳转
三、实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>History 路由</title>
</head>
<body>
<div id="root"></div>
<div id="router-container">
<a href="/home">首页</a>
<a href="/about">关于</a>
<a href="/contact">联系</a>
</div>
<script>
class HistoryRouter {
constructor() {
this.routes = {};
this.currentUrl = "";
this.container = document.getElementById("root");
this.init();
}
init() {
window.addEventListener("load", this.refresh.bind(this), false);
window.addEventListener("popstate", this.refresh.bind(this), false);
}
route(path, callback) {
this.routes[path] = callback || function () {};
}
refresh() {
this.currentUrl = location.pathname || "/";
this.routes[this.currentUrl]?.();
}
render(html) {
this.container.innerHTML = html;
}
push(path) {
history.pushState({}, null, path);
this.routes[path]?.();
}
replace(path) {
history.replaceState({}, null, path);
this.routes[path]?.();
}
}
const router = new HistoryRouter();
router.route("/", () => {
router.render("<h1>首页</h1>");
});
router.route("/home", () => {
router.render("<h1>首页</h1>");
});
router.route("/about", () => {
router.render("<h1>关于</h1>");
});
router.route("/contact", () => {
router.render("<h1>联系</h1>");
});
setTimeout(() => {
router.push("/home");
}, 1000);
</script>
</body>
</html>
四、问题
4.1 Hash
模式与 History
模式的区别?
表现上: hash
模式 url
里面永远带着#号,开发当中默认使用这个模式。如果用户考虑url
的规范那么就需要使用history
模式,因为history
模式没有#
号,是个正常的url
,适合推广宣传;
行为上: 使用 history
模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404
错误,那么就需要和后端人配合,让他配置一下 apache
或是 nginx
的url
重定向,重定向到你的首页路由上就ok了
调用方法上: 调用 history.pushState()
相比于直接修改 hash
,存在以下优势:
-
pushState()
设置的新URL
可以是与当前URL
同源的任意URL
; 而hash
只可修改#
后面的部分,因此只能设置与当前URL
同文档的URL
-
pushState()
设置的新URL
可以与当前URL
一模一样,这样也会把记录添加到栈中;hash
设置的新值必须与原来不一样才会触发动作将记录添加到栈中 -
pushState()
通过stateObject
参数可以添加任意类型的数据到记录中; 而hash
只可添加短字符串pushState()
可额外设置title
属性供后续使用