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

news/2024/9/17 3:34:18/ 标签: vue.js, 前端

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: '<h1>Home Page</h1>' },{ path: '/about', component: '<h1>About Page</h1>' },{ path: '/contact', component: '<h1>Contact Page</h1>' },];// 创建路由实例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 改变 URLwindow.history.pushState({}, '', path);this.onPathChange();}
}

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

<div id="app"></div>
<nav><a href="/" data-link>Home</a><a href="/about" data-link>About</a><a href="/contact" data-link>Contact</a>
</nav><script>// 定义路由规则const routes = [{ path: '/', component: '<h1>Home Page</h1>' },{ path: '/about', component: '<h1>About Page</h1>' },{ path: '/contact', component: '<h1>Contact Page</h1>' },];// 创建路由实例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 应用。


http://www.ppmy.cn/news/1522289.html

相关文章

解决启动Nginx时80端口被占用的问题

文章目录 前言 解决方法1. 搜索服务打开![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c7600d266d194bdb864f7660a5bc5890.png)2. 找到World Wide Web 发布服务这个服务&#xff0c;右键属性&#xff0c;将它的启动类型改为手动&#xff0c;然后停止掉该服务。3. 此…

mysql笔记—基础

1.SQL语句 DDL&#xff08;数据库对象操作&#xff09;、DML&#xff08;增删改&#xff09;、DQL&#xff08;查询&#xff09;、DCL&#xff08;用户和权限操作&#xff09; 2.DDL&#xff1a; 1.数据库操作&#xff1a; show databases; create database []; use []; sele…

oracle数据块内部结构详解

文章目录 Oracle数据块详解概述Oracle块具有以下特点&#xff1a;① 最小的I/O单元&#xff1b;② 包含一个或多个OS块&#xff1b;③ 大小由参数DB_BLOCK_SIZE决定&#xff1b;④ 数据库创建时设置&#xff0c;数据库创建后不能更改 Oracle数据块详解 概述 操作系统块是…

Django跨域问题

简介 由于本站以及很大部分项目都是前后端分离模式&#xff0c;前后端所配置的域名并不相同&#xff0c;所以会受到浏览器的同源策略限制&#xff0c;导致不能正确的请求资源&#xff0c;以下内容先用最简单的方法实现Django后端的跨域问题解决&#xff0c;后续原理再慢慢补充…

ctfshow之文件包含(web78~web86)

web78 if(isset($_GET[file])){$file $_GET[file];include($file); }else{highlight_file(__FILE__); } 解法一&#xff1a;data伪协议 ?filedata://text/plain,<?php system("tac flag.php"); 解法二&#xff1a;php:filter伪协议 ?filepHp://FilTer/conver…

贪心算法求解拆楼房问题

这是一道典型的贪心算法问题&#xff0c;首先遍历找到一个高度大于0的楼房&#xff0c;然后以此为基准&#xff0c;划分一个区间&#xff0c;找到楼房内高度最小的楼房&#xff0c;每次都减去这个高度最小的值。 后续重复一样&#xff0c;再找减去后楼房高度的最小值&#xff…

Springboot工程配置https访问

背景 因为前端工程使用nginx配置了https访问&#xff0c;在https直接请求我们Springboot后端的http接口会报错。那么我们就需要配置使得我们后端的springboot服务支持https访问。 证书生成 在配置springboot工程https之前&#xff0c;我们需要生成自签名证书以及Spring Boot…

中职院校智能物联网应用专业群建设方案

一、引言 随着信息技术的飞速发展&#xff0c;智能物联网&#xff08;IoT&#xff09;作为新一代信息技术的重要组成部分&#xff0c;正深刻改变着人们的生活方式、生产模式和社会形态。为积极响应国家“中国制造2025”和“智慧城市”等战略部署&#xff0c;培养适应未来社会需…

linux使用samba共享目录,其他虚拟机和windows都可以访问

一、192.168.137.12主机作为源目录主机&#xff0c;将/samba/shared_dir目录分享出去 #192.168.137.12主机&#xff1a; rpm -q samba #查看是否安装 yum -y install samba #创建共享目录 mkdir /samba/shared_dir -p #给共享目录赋权 chown -R samba.samba /samba #提示用户不…

CAS与原子操作

什么是原子操作&#xff1f; 原子操作是一种在执行过程中不会被中断的操作。它要么完全执行成功&#xff0c;要么完全不执行&#xff0c;确保在操作完成之前其他线程不会看到操作的中间状态。 原子操作的实现 CAS CAS是由 CPU 提供的原子指令。在硬件级别上确保操作的原子性。…

linux 查看java 进程

在 Linux 中&#xff0c;可以使用以下几种常用方法来查看运行中的 Java 进程&#xff1a; 1. ps 命令 ps 是最常用的查看进程的命令。你可以使用以下命令查看 Java 进程的 PID&#xff1a; ps -ef | grep java-e&#xff1a;显示所有进程。-f&#xff1a;显示完整格式的信息…

斗破C++编程入门系列之二十一:数组、指针和字符串:数组的存储与初始化、对象数组、数组作为函数参数(一星斗师)

斗破C目录&#xff1a; 斗破C编程入门系列之前言&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之二&#xff1a;Qt的使用介绍&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之三&#xff1a;数据结构&#xff08;斗之气三段&#xff09; 斗破C编程入门系列之…

产业生态构建,产业运营服务如何促进上下游协同?

在当今竞争激烈的市场环境中&#xff0c;产业生态的构建成为了企业发展的关键。而产业运营服务作为推动产业生态发展的重要力量&#xff0c;在促进上下游协同方面发挥着至关重要的作用。 首先&#xff0c;产业运营服务通过搭建交流合作平台&#xff0c;促进上下游企业之间的沟通…

2024自动化测试面试真题(附答案)!

一、编程语法题 1 、 python 有哪些数据类型 python 数据类型有很多&#xff0c;基本数据类型有整型&#xff08;数字&#xff09;、字符串、元组、列表、字典和布尔类型等 2 、怎么将两个字典合并 调用字典的 update 方法&#xff0c;合并 2 个字典。 3 、 json.l python 如…

uboot:配置编译

了解BSP 在嵌入式系统中&#xff0c;BSP&#xff08;Board Support Package&#xff09;被称为板级支持包或板级支持软件。它是一组针对特定硬件平台的软件支持包&#xff0c;为开发人员提供了一个统一的接口层&#xff0c;简化了硬件和软件之间的交互。BSP的主要功能和特点如…

HarmonyOS开发实战( Beta5版)不要使用函数/方法作为复用组件的入参规范实践

概述 在滑动场景下&#xff0c;常常会对同一类自定义组件的实例进行频繁的创建与销毁。此时可以考虑通过组件复用减少频繁创建与销毁的能耗。组件复用时&#xff0c;可能存在许多影响组件复用效率的操作&#xff0c;本篇文章将重点介绍如何通过组件复用四板斧提升复用性能。 组…

Cozer必备!一站式解锁扣子全网最全插件集锦(五)

俗话说&#xff0c;工欲善其事必先利其器&#xff01; 用过Coze的朋友都知道&#xff0c;插件在Coze里的重要性。插件库就相当于武器库&#xff0c;一个好的插件&#xff0c;就相当于一件趁手的兵器&#xff0c;可以让你事半功倍&#xff01; 程哥精心整理了Coze最常用和好用…

Vue 3.5 新特性解析

在Vue 3.5中&#xff0c;几个新特性值得关注&#xff0c;它们将极大简化和增强你的开发体验。让我们逐一深入了解这些特性。 1. defineProps支持解构 在Vue 3.5中&#xff0c;defineProps现在支持解构。你可以直接从defineProps中解构出需要的属性&#xff0c;而不必像以前一…

【牛站 / USACO2007】

题目 思路 离散化&#xff08;降低空间复杂度&#xff09; 点的编号 ∈ [ 1 , 1000 ] &#xff0c;但是点的个数最多为 2 ⋅ T ∈ [ 4 , 200 ] 点的编号 \in [1, 1000]&#xff0c;但是点的个数最多为 2 \cdot T \in[4, 200] 点的编号∈[1,1000]&#xff0c;但是点的个数最多为…

手机扬声器音量总是不够大?试试“扬声器助推器”吧

手机的扬声器音量总是不够大&#xff0c;尤其是在嘈杂的环境中&#xff0c;音乐和视频的声音总是不太清晰。直到我发现了这款“扬声器助推器”&#xff0c;我的手机音质瞬间提升了好几个档次。 软件简介&#xff1a; “扬声器助推器”利用先进的音频处理技术&#xff0c;能够…