手写 Vue Router 中的 Hash 模式和 History 模式

Vue Router Vue.js 的官方路由库,负责管理 Vue应用中的页面导航。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。Vue Router 提供两种常见的模式:Hash 模式History 模式。这两种模式的主要区别在于它们如何管理 URL,以及如何与浏览器的历史记录 API 交互。

1. URL 路由的基本概念

Vue RouterVue 官方的客户端路由解决方案。

客户端路由的作用是在单页应用 (SPA) 中将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面时,URL 会随之更新,但页面不需要从服务器重新加载。

Vue Router 基于 Vue 的组件系统构建,你可以通过配置路由来告诉 Vue Router 为每个 URL 路径显示哪些组件。路由的主要任务包括:

  • 根据 URL 切换不同的页面组件。
  • 动态管理浏览器的历史记录和导航状态。

Vue Router 使用两种方式来实现路由:

  • Hash 模式:利用 URL 中的 # 符号(例如 http://example.com/#/home),基于 hashchange事件进行路由切换。
  • History 模式:利用 HTML5 的 History API(pushStatereplaceState)实现路径导航(例如 http://example.com/home),更贴近传统多页面应用的 URL 形式。

2. 实现 Hash 模式的 Vue Router

Hash 模式是最简单的一种实现方式,它依赖于浏览器原生的 hashchange 事件。下面我们通过手写代码实现一个简化版的 Hash 模式。

2.1 Hash 模式核心代码

class Router {
  constructor(routes) {
    this.routes = routes;  // 路由规则
    this.currentPath = ''; // 当前路径

    this.init();
  }

  // 初始化监听
  init() {
    // 页面加载时触发路由匹配
    window.addEventListener('load', this.onHashChange.bind(this));
    // 当 hash 改变时,触发路由匹配
    window.addEventListener('hashchange', this.onHashChange.bind(this));
  }

  // 获取当前 hash 路径并匹配路由
  onHashChange() {
    // 去掉 # 并获取当前的路径
    this.currentPath = window.location.hash.slice(1) || '/';
    this.matchRoute();
  }

  // 匹配路径对应的组件并渲染
  matchRoute() {
    const route = this.routes.find(r => r.path === this.currentPath);
    if (route) {
      document.getElementById('app').innerHTML = route.component;
    } else {
      document.getElementById('app').innerHTML = '404 Not Found';
    }
  }
}

2.2 示例代码
我们可以定义一些简单的路由和组件,并启动这个简化版的 Hash 模式路由。


<div id="app">div>

<script>
  // 定义路由规则
  const routes = [
    { path: '/', component: '

Home Page

'
}, { path: '/about', component: '

About Page

'
}, { path: '/contact', component: '

Contact Page

'
}, ]; // 创建路由实例 const router = new Router(routes);
script>

当用户访问 /#/about 时,hashchange 事件会触发,路由器会匹配 /about 路径,并在页面上渲染 About Page 组件。

2.3 Hash 模式的优缺点

优点:

  • 简单易实现,几乎所有浏览器都支持 hashchange 事件。
  • 不需要服务器配置即可使用,因为 hash 不会被发送到服务器。

缺点:

  • URL 中包含 # 符号,显得不够美观。
  • SEO 不友好,搜索引擎不会解析 # 后面的内容。

3. 实现 History 模式的 Vue Router

vue-router 默认 hash 模式 —— 使用 URLhash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。该模式基于 HTML5 的 pushStatereplaceState API,能够改变浏览器的 URL 而不刷新页面。这种方式让 URL 更加简洁,不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

3.1 History 模式核心代码

class Router {
  constructor(routes) {
    this.routes = routes;  // 路由规则
    this.currentPath = window.location.pathname; // 当前路径

    this.init();
  }

  // 初始化监听
  init() {
    // 页面加载时触发路由匹配
    window.addEventListener('load', this.onPathChange.bind(this));
    // 浏览器前进后退时触发路由匹配
    window.addEventListener('popstate', this.onPathChange.bind(this));

    // 绑定导航点击事件
    document.querySelectorAll('a[data-link]').forEach(link => {
      link.addEventListener('click', this.onLinkClick.bind(this));
    });
  }

  // 处理路径变化
  onPathChange() {
    this.currentPath = window.location.pathname;
    this.matchRoute();
  }

  // 匹配路径并渲染组件
  matchRoute() {
    const route = this.routes.find(r => r.path === this.currentPath);
    if (route) {
      document.getElementById('app').innerHTML = route.component;
    } else {
      document.getElementById('app').innerHTML = '404 Not Found';
    }
  }

  // 拦截导航链接点击事件
  onLinkClick(event) {
    event.preventDefault();
    const path = event.target.getAttribute('href');
    // 使用 pushState 改变 URL
    window.history.pushState({}, '', path);
    this.onPathChange();
  }
}

3.2 示例代码
为配合 pushState 的使用,我们需要在页面上创建一些导航链接,并通过点击这些链接进行页面切换。

<div id="app">div>
<nav>
  <a href="/" data-link>Homea>
  <a href="/about" data-link>Abouta>
  <a href="/contact" data-link>Contacta>
nav>

<script>
  // 定义路由规则
  const routes = [
    { path: '/', component: '

Home Page

'
}, { path: '/about', component: '

About Page

'
}, { path: '/contact', component: '

Contact Page

'
}, ]; // 创建路由实例 const router = new Router(routes);
script>

在这个示例中,当点击导航链接时,pushState 改变 URL,但不会触发页面刷新,而是通过 Router 手动渲染对应的组件。

3.3 History 模式的优缺点

优点:

  • URL 更加美观,没有 # 符号。
  • 更加符合传统的多页面应用,用户体验更好。
  • SEO 更友好,搜索引擎可以解析 URL

缺点:
-需要服务器配合,所有请求必须返回 index.html,否则会出现 404 错误。

4. 总结

通过手写简化版的 Vue Router,我们深入理解了 Hash 模式History 模式 的实现原理。Hash 模式依赖于 hashchange 事件,而 History 模式依赖于 pushStatereplaceState API。两种模式各有优缺点,可以根据项目需求选择合适的路由模式。

  • Hash 模式:简单、无需服务器配置,但 URL 不美观,对 SEO 不友好。
  • History 模式:URL 美观且符合 SEO 要求,但需要服务器支持。

无论是简单的项目还是大型的单页面应用,Vue Router 都提供了强大的路由管理能力,通过深入了解其原理,我们可以更灵活地运用它来构建现代 Web 应用。

你可能感兴趣的:(vue.js,前端)