跳到主要内容

Hash 路由

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

一、认识


Hash 模式 在浏览器中符号#,# 以及 # 后面的字符称之为 hash。用 window.location.hash 读取。hash 虽然在 URL 中,但不被包括在 HTTP 请求中; 用来指导浏览器动作,对服务端安全无用,hash 不会重加载页面

二、思路


  • URL 中的 hash 值只是客户端的一种状态,向服务端发送请求的时候,hash 部分不会被发送。

  • hash 值得改变会在浏览器的历史记增加访问记录,所以可以通过浏览器的回退、前进控制 hash 值的改变。

  • 可以通过 a 标签设置 href 值或者通过 jslocation.hash 赋值来改变 hash 值。

  • 可以通过 hashchang 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

三、实现


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hash 路由</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 HashRouter {
constructor() {
this.routes = {};
this.currentUrl = "";
this.container = document.getElementById("root");

this.init();
}

init() {
window.addEventListener("load", this.refresh.bind(this), false);
window.addEventListener("hashchange", this.refresh.bind(this), false);
}

route(path, callback) {
this.routes[path] = callback || function () {};
}

refresh() {
this.currentUrl = location.hash.slice(1) || "/";
this.routes[this.currentUrl]?.();
}

render(html) {
this.container.innerHTML = html;
}

push(path) {
location.hash = path;
}
}

const router = new HashRouter();
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>");
});
</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 属性供后续使用