适用读者:所有 Node.js 和前端开发者,特别是那些希望构建单页应用(SPA)、理解前端路由原理,或需要处理包含哈希的 URL 的工程师
目标:精通 Node.js URL 类的 hash 属性,理解哈希路由的工作原理,并能构建一个支持无刷新导航的客户端路由系统


1. URL Hash:不止是一个 # 符号

在 URL 中,哈希(Hash)或片段标识符(Fragment Identifier)是 # 符号及其后面的部分。例如,在 https://example.com/page#section-2 中,#section-2 就是哈希。
传统用途:最初,哈希主要用于定位 HTML 页面内的特定锚点(<a name="section-2">),让浏览器直接滚动到页面的某个部分。
现代用途:在现代 Web 开发中,哈希被赋予了更重要的使命——实现客户端路由,它是构建单页应用(SPA)的基石之一。

2. 核心方法解析:url.hash 属性

在 Node.js 中,new URL() 构造函数会解析一个 URL 字符串,并将其各个部分作为属性提供。hash 属性就是用来获取和设置哈希部分的。

const { URL } = require('url');
const myUrl = new URL('https://example.com/path?query=123#section-2');
// 获取哈希
console.log(myUrl.hash); // 输出: '#section-2'
// 设置哈希
myUrl.hash = '#new-section';
console.log(myUrl.href); // 输出: 'https://example.com/path?query=123#new-section'
// 如果哈希为空
const urlWithoutHash = new URL('https://example.com/path');
console.log(urlWithoutHash.hash); // 输出: ''

关键特性

  • 包含 # 符号hash 属性的值包含前导的 #
  • 编码处理URL 类会自动处理哈希中的特殊字符编码。
  • 对服务器透明:哈希部分永远不会被发送到服务器。浏览器在发起 HTTP 请求时,会自动截断 # 及其后的内容。这是它能用于客户端路由的根本原因。

3. 实战:构建一个支持哈希路由的 SPA

让我们构建一个简单的例子,演示哈希路由如何工作。我们将有一个 Express 后端和一个前端 HTML 文件。

3.1 后端代码

// server.js
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000;
// 托管静态文件(如 CSS, JS)
app.use(express.static('public'));
// 所有路由都返回同一个 index.html 文件
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'views', 'index.html'));
});
app.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`);
});

3.2 前端代码

<!-- views/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hash Routing Demo</title>
  <style>
    .content { margin-top: 20px; padding: 10px; border: 1px solid #ccc; }
    nav a { margin-right: 10px; }
  </style>
</head>
<body>
  <h1>My Single Page App</h1>
  <nav>
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </nav>
  <div id="content" class="content">
    <!-- Content will be loaded here -->
  </div>
  <script>
    const contentDiv = document.getElementById('content');
    // 路由配置
    const routes = {
      '#home': '<h2>Home Page</h2><p>Welcome to the homepage!</p>',
      '#about': '<h2>About Us</h2><p>This is a demo of hash routing.</p>',
      '#contact': '<h2>Contact</h2><p>Contact us at info@example.com.</p>'
    };
    // 路由函数
    function router() {
      const hash = window.location.hash || '#home'; // 默认为 home
      contentDiv.innerHTML = routes[hash] || '<h2>404 Not Found</h2>';
    }
    // 监听哈希变化事件
    window.addEventListener('hashchange', router);
    // 页面首次加载时执行一次路由
    window.addEventListener('load', router);
  </script>
</body>
</html>

工作流程

  1. 用户访问 http://localhost:3000,Express 返回 index.html
  2. 页面加载后,JS 代码执行,window.location.hash 为空,因此显示 #home 的内容。
  3. 用户点击 <a href="#about"> 链接。
  4. 浏览器地址栏变为 http://localhost:3000/#about,但不会向服务器发起新请求
  5. hashchange 事件被触发,router() 函数执行,更新 contentDiv 的内容为 “About” 页面的内容。
  6. 整个过程无刷新,用户体验流畅。

4. 哈希路由 vs. History API 路由

除了哈希路由,现代前端框架(如 React Router, Vue Router)更推荐使用 History API 来实现更“干净”的路由(如 /about 而不是 /#about)。

特性哈希路由History API 路由
URL 格式example.com/#aboutexample.com/about
美观度较差,有一个 #优秀,看起来像传统 URL
兼容性极好,兼容所有浏览器较好,需要 HTML5 支持(IE10+)
服务器配置无需特殊配置需要配置,服务器必须将所有路由都指向 index.html
部署难度简单稍复杂,需配合后端
如何选择?
  • 选择哈希路由:如果你需要兼容非常老的浏览器,或者你的部署环境非常受限,无法配置服务器回退(fallback)规则。
  • 选择 History API:对于绝大多数现代 Web 应用,这是首选。它提供了更美观、更符合 SEO 最佳实践的 URL。

5. 总结与最佳实践

5.1 关键概念回顾

  • URL Hash (#) 是片段标识符,不会发送到服务器
  • url.hash 属性在 Node.js 中用于获取和设置 URL 的哈希部分。
  • 哈希路由是构建 SPA 的经典方法,通过监听 hashchange 事件实现无刷新导航。
  • 哈希路由兼容性极佳,但 URL 格式不如 History API 美观。

5.2 URL 处理最佳实践清单

  • 在 SPA 中使用哈希路由作为简单、兼容性好的客户端路由方案。
  • 始终监听 hashchange 事件来响应路由变化。
  • 为首次访问设置默认路由(如 #home)。
  • 在新项目中优先考虑 History API,除非有特殊的兼容性或部署要求。
  • 理解哈希对服务器不可见,不要期望在后端通过 req.url 获取到哈希值。

5.3 进阶学习路径

  1. 深入学习 History API:掌握 history.pushState()history.replaceState(),以及如何配合后端实现服务端渲染(SSR)和 SEO 友好的路由。
  2. 研究前端路由库:阅读 react-routervue-router 的源码,理解它们是如何封装和抽象路由逻辑的。
  3. 服务端渲染(SSR):了解如何在服务器端根据 URL 路径渲染出完整的 HTML 页面,以获得更好的首屏加载性能和 SEO。
  4. URL 编码:学习 encodeURIComponent()decodeURIComponent(),正确处理 URL 中的特殊字符。

5.4 资源推荐


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐