vue react路由底层原理 | Hash & histroy 模式

14 阅读5分钟

一、前端路由原理

1. SPA(单页面应用)

单页面应用(Single Page Application)是一种只加载一次 HTML 页面并在用户与应用交互时动态更新页面内容的 Web 应用。浏览器在首次加载时会获取所需的 HTML、CSS 和 JavaScript 文件,之后所有的操作都通过 JavaScript 控制。这种模式非常适合现代 Web 应用,因为它可以提供流畅的用户体验。

我们结合 react 项目来理解就是 index.html 页面提供挂载点和 js 的引用

2. 路由的必要性

对于复杂的 SPA 应用,路由是不可或缺的。路由允许开发者在不同的页面之间切换,而无需重新加载整个页面。Vue 和 React 都提供了强大的路由功能,无论React 还是 Vue 的 router 都支持两种模式:Hash 模式和 History 模式。

我们先来看看 Hash 和 histroy 的核心差异

二、Hash 模式

1. 定义

Hash 模式是一种通过在 URL 中添加 # 符号来实现前端路由的方式。浏览器在检测到 # 后的路径变化时,不会重新发起请求,而是触发 onhashchange 事件。

2. 网页 URL 组成部分

  • location.protocol:协议(如 http:
  • location.hostname:主机名(如 127.0.0.1
  • location.host:主机(如 127.0.0.1:8001
  • location.port:端口号(如 8001
  • location.pathname:访问页面(如 01-hash.html
  • location.search:搜索内容(如 ?a=100&b=20
  • location.hash:哈希值(如 #/aaa/bbb

3. Hash 的特点

  • 无刷新跳转:Hash 变化不会触发页面刷新,因此不会重新加载资源。
  • 浏览器兼容性:Hash 模式兼容性较好,几乎所有现代浏览器都支持。
  • SEO 限制:Hash 模式下的 URL 不会被搜索引擎爬虫完全解析,因此不利于 SEO。
  • 灵活性:Hash 模式只能修改 # 后面的部分,因此只能跳转到同文档的 URL。

4. Hash 模式的应用场景

  • To B 系统:企业内部系统通常对 SEO 要求不高,Hash 模式简单易用,适合快速开发。
  • 小型项目:对于功能简单的项目,Hash 模式可以快速实现路由功能。

5. 案例与代码示例

以下是一个简单的 Hash 模式实现:

// 监听 hash 变化
window.addEventListener('hashchange', function() {
  console.log('Hash changed to:', location.hash);
  // 根据 hash 值加载对应的内容
  loadContent(location.hash);
});

// 初始加载
window.addEventListener('load', function() {
  console.log('Initial hash:', location.hash);
  loadContent(location.hash);
});

function loadContent(hash) {
  // 根据 hash 值加载内容
  if (hash === '#/home') {
    console.log('Loading home page...');
  } else if (hash === '#/about') {
    console.log('Loading about page...');
  } else {
    console.log('Loading default page...');
  }
}

三、History 模式

1. 定义

History 模式是 HTML5 提供的新特性,允许开发者直接更改前端路由,更新浏览器 URL 地址而不重新发起请求。

2. 与 Hash 模式的区别

通过一个例子来说明 Hash 和 History 模式在浏览器刷新时的区别:

  • 正常页面浏览
    • https://github.com/xxx 刷新页面
    • https://github.com/xxx/yyy 刷新页面
    • https://github.com/xxx/yyy/zzz 刷新页面
  • History 模式
    • https://github.com/xxx 刷新页面
    • https://github.com/xxx/yyy 前端跳转,不刷新页面
    • https://github.com/xxx/yyy/zzz 前端跳转,不刷新页面

3. History 的 API

  • history.pushState(data, title [, url]):向历史记录堆栈顶部添加一条记录。
  • history.replaceState(data, title [, url]):更改当前的历史记录。
  • history.state:存储 pushStatereplaceState 的数据。
  • window.onpopstate:响应 pushStatereplaceState 的调用。

4. History 的特点

  • 无刷新跳转:通过 pushStatereplaceState 实现无刷新跳转。
  • SEO 友好:URL 更加规范,适合搜索引擎爬虫解析。
  • 服务端支持:需要服务端配置,否则刷新页面会导致 404 错误。

5. History 模式的应用场景

  • To C 系统:面向用户的系统通常对 SEO 要求较高,History 模式更适合。
  • 大型项目:功能复杂的项目需要更灵活的路由管理,History 模式可以提供更好的用户体验。

6. 案例与代码示例

以下是一个简单的 History 模式实现:

// 使用 pushState 添加历史记录
function navigateTo(url) {
  history.pushState({}, '', url);
  loadContent(url);
}

// 监听 popstate 事件
window.addEventListener('popstate', function() {
  loadContent(location.pathname);
});

function loadContent(path) {
  // 根据路径加载内容
  if (path === '/home') {
    console.log('Loading home page...');
  } else if (path === '/about') {
    console.log('Loading about page...');
  } else {
    console.log('Loading default page...');
  }
}

// 初始加载
loadContent(location.pathname);

7. 服务端配置示例(Nginx)

为了支持 History 模式,需要在服务端配置中确保所有路由都指向主页面:

server {
  listen 80;
  server_name example.com;

  location / {
    try_files $uri /index.html;
  }
}

四、两者的选择

在实际项目中,选择 Hash 模式还是 History 模式需要根据具体需求和场景来决定:

  • To B 系统:推荐使用 Hash 模式,因为它相对简单,且对 URL 规范不敏感。
  • To C 系统:可以考虑使用 History 模式,但需要服务端支持。
  • 成本与收益:能用简单的解决方案就不要用复杂的,尽量平衡开发成本和用户体验。

五、性能优化与最佳实践

1. 性能优化

  • 减少不必要的渲染:通过路由守卫或懒加载减少不必要的组件渲染。
  • 缓存策略:合理使用缓存策略,减少网络请求。
  • 代码分割:将路由相关的代码进行分割,按需加载。

2. 最佳实践

  • 统一的路由管理:使用路由库(如 Vue Router 或 React Router)统一管理路由。
  • 路由验证:在路由切换时进行权限验证,确保用户只能访问授权的页面。
  • 错误处理:捕获路由切换时的错误,提供友好的错误提示。

六、总结

Hash 和 History 模式各有优缺点,了解它们的区别和适用场景是前端开发中的重要技能。本文对前端路由原理进行了深入探讨,希望能为大家提供一些帮助。通过合理选择和优化,可以为用户提供一个流畅且高效的用户体验。

参考资料