跳到主要内容

History 路由

2024年03月06日
柏拉文
越努力,越幸运

一、认识


History 模式 采用 HTML5 的新特性, 且提供了两个新方法: pushState()replaceState()可以对浏览器历史记录栈进行修改,以及 popState 事件的监听到状态变更。pushState方法、replaceState方法,只能导致history对象发生变化,从而改变当前地址栏的 URL,但浏览器不会向后端发送请求,也不会触发popstate事件的执行。popstate 事件的执行是在点击浏览器的前进后退按钮的时候,才会被触发

二、思路


  • 通过 pushStatereplaceState 两个 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 或是 nginxurl 重定向,重定向到你的首页路由上就ok了

调用方法上: 调用 history.pushState() 相比于直接修改 hash,存在以下优势:

  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL; 而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL

  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中; hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中

  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中; 而 hash 只可添加短字符串 pushState() 可额外设置 title 属性供后续使用