当前位置: 首页 > article >正文

前端框架Vue的路由机制

大家好,我是G探险者。

最近在调试前端代码的时候,遇到一个问题。首先我们有一个门户页面,该页面里面有很多的豆腐块,每个豆腐块会配置一个系统的跳转连接。


我的系统就是其中一个豆腐块,我第一次登录进来之后,点击我的系统豆腐块可以正常跳转,页面加载都正常,但是切出之后,再次点击我的豆腐块,报了404,页面莫名其妙就找不到了。

为了弄清这个原因,最后研究发现有几个关键的技术点:前端路由,路由模式的两种模式(history模式和hash模式),单页面应用(SPA).

下面我将从这几个概念介绍。

一、单页面(SPA)与多页面(MPA)

什么是单页面应用(SPA)?

单页面应用(Single Page Application,简称 SPA)是一种通过 JavaScript 和客户端路由来实现的 web 应用程序,它的特点是:

  • 一次性加载:SPA 应用在首次加载时加载整个应用的 HTML、CSS 和 JavaScript 文件。之后的所有页面更新都是通过 JavaScript 动态加载数据并在当前页面中更新视图,而不会重新加载整个页面。
  • 页面切换无刷新:用户在浏览不同页面时,SPA 不会向服务器请求新的 HTML 页面,而是通过 JavaScript 动态更新视图,模拟页面跳转的效果。页面切换时,URL 通常也会发生变化,但不会引起浏览器的全页面刷新。
  • 客户端渲染:所有的视图渲染工作主要在客户端完成,后端通常只负责提供数据接口(如 API)而不参与页面渲染。

SPA 的工作原理:

  • 当用户首次访问时,浏览器从服务器加载一个 HTML 文件,加载相关的 JavaScript 文件和资源。
  • 后续用户与应用交互时,通过 JavaScript 操控页面内容,通常使用客户端路由(如 vue-routerreact-router)来管理不同的视图状态。
  • URL 会根据不同的路由更新,但页面内容不会刷新,只有相关的数据和视图组件会被更新。

SPA 的优缺点:

  • 优点
    1. 流畅的用户体验:因为没有页面刷新,用户的交互体验更加平滑、响应迅速。
    2. 前后端分离:后端主要提供数据接口,前端可以独立于后端开发。
    3. 减少网络请求:页面资源一次加载后,后续操作仅需请求 API 接口而不是完整页面。
  • 缺点
    1. SEO 问题:传统的 SPA 使用 JavaScript 动态渲染页面内容,搜索引擎的爬虫可能无法正确索引这些动态内容。为了解决这个问题,通常需要使用服务器端渲染(SSR)或预渲染技术。
    2. 首次加载较慢:SPA 通常需要在初始加载时加载大量的 JavaScript 代码,可能会导致首次加载较慢。
    3. 浏览器性能压力:因为所有的渲染都在客户端进行,大量的 JavaScript 代码和复杂的应用逻辑可能会导致浏览器性能下降。

什么是多页面应用(MPA)?

多页面应用(Multi-Page Application,简称 MPA)是传统的 web 应用形式,指的是一个应用包含多个独立的页面,每个页面由服务器根据请求动态渲染,并且每次用户跳转到新页面时,浏览器都会发起新的 HTTP 请求,重新加载整个页面。

MPA 的工作原理:

  • 每次用户请求一个新的页面时,浏览器都会向服务器发起请求,服务器返回一个完整的 HTML 页面,并加载该页面的 CSS 和 JavaScript 资源。
  • 页面间的跳转会导致整个页面的重新加载,服务器负责渲染新的页面内容并返回。
  • MPA 的每个页面通常是相互独立的,互不干扰。

MPA 的优缺点:

  • 优点

    1. SEO 友好:每个页面都是一个独立的 HTML 页面,可以被搜索引擎正常索引,因此 SEO 表现更好。
    2. 简单实现:没有太多复杂的前端 JavaScript 逻辑,适合于简单的网站或传统的多页面网站。
    3. 更好的初始加载速度:由于每个页面都是独立加载的,首屏加载速度通常较快。
  • 缺点

    1. 较差的用户体验:每次页面跳转都会重新加载整个页面,体验上不如 SPA 流畅。
    2. 页面之间的数据共享困难:每个页面都是独立的,页面之间的状态和数据不容易共享。
    3. 需要更多的网络请求:每次跳转都会向服务器请求完整的页面和资源,增加了服务器负担和网络流量。

SPA 和 MPA 的区别

特性单页面应用(SPA)多页面应用(MPA)
页面切换页面不刷新,内容局部更新,流畅的用户体验每次跳转都刷新整个页面
请求次数初次加载时请求资源,后续通过 API 获取数据每次跳转都向服务器请求完整的页面资源
URL 变化使用前端路由控制,URL 改变但不刷新页面每次跳转都会改变 URL 并刷新页面
开发方式前后端分离,前端多使用 JavaScript 控制视图后端渲染页面,前端通常更依赖服务器渲染内容
SEOSEO 难度较大,通常需要服务器端渲染(SSR)或预渲染由于每个页面是独立的,SEO 更加友好
性能初次加载较慢,但后续操作快速每个页面都重新加载,可能导致性能问题
适用场景适用于需要流畅交互、丰富功能的现代 Web 应用适用于传统的网站、内容较少、页面之间差异大的场景

适用场景分析

  • SPA 适用场景

    1. 动态内容丰富的 Web 应用:如社交媒体平台、在线编辑器、管理后台、即时聊天应用等。
    2. 需要良好用户体验的应用:例如需要实现流畅的动画效果、快速切换视图等的应用。
    3. 前后端分离的项目:适合团队分工明确,前端和后端开发可以独立进行的项目。
  • MPA 适用场景

    1. 内容较少且结构简单的网站:如公司官网、博客、新闻网站等。
    2. SEO 需求较高的项目:例如电商平台、搜索引擎优化要求较高的博客或内容网站。
    3. 需要快速初始加载速度的网站:MPA 通常首屏加载速度较快,适用于静态内容较多的网站。

二、前端路由

什么是前端路由?

前端路由是指,在用户的浏览器端(客户端)处理路由跳转,而无需向服务器请求新的页面。在传统的多页面应用(MPA)中,每次用户点击链接或刷新页面时,浏览器会向服务器发送请求,服务器返回完整的页面。然而,在前端路由的 SPA 应用中,页面加载一次后,应用的所有路由跳转都只是在浏览器端通过 JavaScript 控制视图的切换,而不会重新加载整个页面。

Vue Router 的基本工作原理

Vue Router 基本上是根据 URL 的变化来决定显示哪个视图(组件)。其核心原理是:

  • 通过监听浏览器的 URL(或地址栏)的变化,Vue Router 决定展示哪个组件。
  • 根据定义的路由规则,URL 的不同部分(路径、查询参数、哈希等)会映射到不同的组件。
  • Vue Router 在 URL 改变时,更新浏览器的历史记录(这通过 History API 或 hashchange 事件来实现)。

具体来说,Vue Router 通过以下机制工作:

  • 路由规则(Routes):定义 URL 路径与视图组件的映射关系。
  • 路由模式(Mode):定义 URL 是如何呈现的,常见的有 hash 模式和 history 模式。
  • 路由守卫(Navigation Guards):在路由切换时,提供钩子函数来做路由拦截、权限验证等操作。

Vue Router 核心概念

路由定义与路由表

Vue Router 的核心是路由表,它通过路径匹配将 URL 映射到组件。通常,路由表定义在一个 routes 数组中,每个路由对象包含以下内容:

  • path:路由的路径。
  • component:该路径对应的组件。
  • name:可选的路由名字,可以用于通过名称进行导航。
  • children:嵌套路由,定义父子路由关系。
  • meta:用于存放额外信息,如权限等。

视图组件与 <router-view>

路由表定义的组件会通过 <router-view> 显示在页面中。<router-view> 是一个占位符,它会根据路由的变化渲染对应的组件。

<!-- App.vue -->
<template>
  <div>
    <h1>Vue Router 示例</h1>
    <router-view></router-view> <!-- 根据路由渲染对应的组件 -->
  </div>
</template>

当你在浏览器中切换不同的 URL 路径时,<router-view> 会自动渲染出与当前路径匹配的组件。

动态路由与路由参数

Vue Router 还支持动态路由,它允许你在 URL 中定义动态部分。例如,路径 /user/:id 中的 :id 就是一个动态参数,可以在组件中获取到这个参数的值。

const routes = [
  {
    path: '/user/:id',
    component: User,
    props: true // 使动态路径参数通过 props 传递给组件
  }
];

通过 this.$route.params.id 访问动态参数 id

路由嵌套(Nested Routes)

你可以通过 children 属性定义嵌套路由,这样可以实现多层视图的嵌套展示。例如,父组件内嵌套多个子组件。

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    children: [
      {
        path: 'profile',
        component: Profile
      },
      {
        path: 'settings',
        component: Settings
      }
    ]
  }
];

在父组件的模板中,使用 <router-view> 来嵌套显示子路由的视图:

<!-- Dashboard.vue -->
<template>
  <div>
    <h2>Dashboard</h2>
    <router-view></router-view> <!-- 子路由会渲染在这里 -->
  </div>
</template>

路由守卫(Navigation Guards)

路由守卫是 Vue Router 提供的一种机制,可以在路由跳转时执行特定的逻辑,比如权限验证、数据预加载等。常见的路由守卫有:

  • 全局守卫:可以在任何路由切换前、后或解析时触发。
    • beforeEach: 在路由跳转前执行。
    • afterEach: 在路由跳转后执行。
router.beforeEach((to, from, next) => {
  // 执行权限检查等
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login'); // 跳转到登录页
  } else {
    next(); // 继续路由跳转
  }
});
  • 路由独享守卫:每个路由配置项中可以定义 beforeEnter 来指定独享的守卫。
  • 组件内守卫:在组件内部定义 beforeRouteEnterbeforeRouteUpdate 和 beforeRouteLeave 来管理路由状态。

程序化导航(Programmatic Navigation)

除了 <router-link> 组件,Vue Router 还提供了编程式导航的方式来跳转路由。你可以通过调用 this.$router.push() 或 this.$router.replace() 方法来导航。

this.$router.push('/home'); // 导航到 /home
this.$router.push({ name: 'user', params: { id: 123 } }); // 根据路由名称和参数跳转

路由模式(Hash 与 History)

Vue Router 支持两种主要的路由模式:hash 模式和 history 模式。

Hash 模式

工作原理
  • 在 hash 模式 中,路由会通过 URL 中的 hash(#)符号 来进行区分。例如,http://example.com/#/home
  • # 后面的部分不会被浏览器提交给服务器,所有的页面变化都发生在浏览器端,而不会导致页面刷新。
  • 当用户访问 http://example.com/#/home 时,# 后面的部分会被用作路由的标识,浏览器不会向服务器发送请求。
优点
  • 无需服务器配置:在 hash 模式下,浏览器不会向服务器发送带有 # 的 URL 部分。因此,不需要特别的服务器配置就能支持路由。
  • 兼容性好hash 模式的历史记录由浏览器内建支持,且几乎所有现代浏览器(包括早期版本的浏览器)都能兼容 hash 模式。
  • 易于实现hash 模式实现简单,开发时不需要考虑与服务器的配合,适合快速开发和部署。
缺点
  • URL 不够美观:URL 中有 # 符号,可能影响用户的体验,并且不如 history 模式的 URL 更符合常规的 URL 格式。例如,http://example.com/#/home
  • SEO 较差:由于哈希部分(# 后面的部分)不被浏览器作为正常 URL 发送给服务器,搜索引擎的爬虫可能无法抓取和索引这些页面,影响 SEO。
适用场景
  • 静态网站:如果你在开发的是一个静态网站或不依赖于复杂服务器配置的应用,hash 模式是一个简单且快速的选择。
  • 没有后端服务器支持的应用:如果你没有对服务器进行配置(比如静态托管在某些第三方平台上,无法配置服务器的 URL 重写规则),hash 模式是最适合的选择。
  • 早期浏览器兼容:如果你的应用需要支持较旧的浏览器,hash 模式因为其广泛的兼容性,通常是首选。

History 模式

工作原理
  • history 模式 基于 HTML5 的 History API,通过调用 pushState 和 replaceState 来改变浏览器的 URL,而无需刷新页面。例如,http://example.com/home
  • 这种模式下,URL 不包含 # 符号,看起来与传统的多页面应用相似。
优点
  • 美观的 URLhistory 模式生成的 URL 更加清晰和符合常规,例如 http://example.com/home,不包含 # 符号,更加符合 SEO 和用户习惯。
  • 更好的 SEO:因为 URL 中不包含哈希符号,搜索引擎可以正常地抓取页面内容,优化 SEO 表现。
  • 更接近传统网站history 模式下的 URL 和多页面应用的行为类似,因此适合需要多页面结构的应用,且能够提供无刷新页面切换的体验。
缺点
  • 需要服务器配置history 模式依赖于 HTML5 的 History API,浏览器的 URL 会发生变化,因此需要服务器端配置支持路由。例如,如果用户直接访问 http://example.com/home,而服务器没有配置该路径的处理规则,可能会返回 404 错误。
  • 浏览器兼容性:虽然大多数现代浏览器都支持 history API,但某些老旧浏览器可能不兼容,尤其是 Internet Explorer 9 及以下版本。
适用场景
  • 服务器支持:当你可以控制服务器的配置,能够对所有 URL 路径进行重定向处理时,history 模式是一个理想的选择。例如,在服务器上配置 URL 重写规则,使得所有路径都指向应用的 index.html 文件。
  • SEO 要求较高的应用:如果你的应用需要考虑 SEO,且你希望 URL 结构尽量简洁、干净,history 模式是首选,因为它不会在 URL 中添加 # 符号。
  • 现代浏览器和单页面应用:适用于现代浏览器,尤其是需要构建复杂、功能丰富的 SPA 应用时,history 模式提供更好的体验。

如何选择:Hash 模式 vs History 模式

选择标准Hash 模式History 模式
SEO 需求SEO 支持较差,因为 URL 中有 #SEO 更好,因为 URL 看起来是常规的路径。
浏览器兼容性兼容性广,支持所有浏览器。现代浏览器支持较好,较老版本浏览器支持差。
服务器支持不需要服务器配置。需要服务器配置,支持 URL 重写。
URL 美观度URL 包含 #,不太美观。URL 简洁、符合标准,像传统的多页面应用。
适用场景静态网站、没有后端支持的应用、早期浏览器支持需要 SEO 和美观 URL 的应用、需要服务器支持

为什么History 模式需要服务器配置?

在 History 模式 中,前端应用使用 HTML5 History APIpushState 和 replaceState)来控制 URL 的变化。当用户访问某个路径时,例如 http://example.com/home,浏览器不会向服务器请求 home 页面,而是由前端路由框架(如 Vue Router)来渲染视图。但当用户直接刷新页面或通过直接访问 URL 时,浏览器会向服务器请求 http://example.com/home 这个路径。

问题:服务器并不知道该如何处理这个请求。因为这个路径 /home 并不是服务器上存在的文件或页面,而是由前端路由生成的。

  • 如果你没有进行服务器配置,服务器会返回一个 404 错误,说明它找不到 /home 这个资源。
  • 如果你配置了服务器,使得所有路径都指向你的前端应用的入口页面(例如 index.html),前端路由框架会接管路由控制,正确渲染页面。

举例说明:

假设你有一个 Vue.js 项目,使用了 Vue Router 并且设置了 History 模式。你的应用有两个页面:

  • /home(主页)
  • /about(关于页)

如果你访问 http://example.com/home,前端路由框架会根据 URL 渲染 home 页面,但 如果没有服务器配置,直接刷新页面时,浏览器会向服务器请求 http://example.com/home,而此时服务器并没有 /home 这个路径的实际文件,所以它会返回 404 错误。

服务器配置的作用:

为了避免这个问题,通常会进行如下配置:

  • 服务器需要将所有的路由请求(如 /home/about)都指向应用的 index.html 文件,然后由前端的路由框架(如 Vue Router)来接管具体的路由渲染。

举例:Apache 服务器配置

在 Apache 服务器中,可以通过设置 .htaccess 文件来实现 URL 重写,将所有的请求都指向 index.html

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]
  • 解释
    • RewriteEngine On:开启重写功能。
    • RewriteCond %{REQUEST_FILENAME} !-f:如果请求的文件不存在。
    • RewriteCond %{REQUEST_FILENAME} !-d:如果请求的目录不存在。
    • RewriteRule ^ index.html [L]:将所有请求重写到 index.html,并由前端路由来处理。

通过这种配置,当用户直接访问 http://example.com/home 或者刷新这个页面时,Apache 会返回 index.html 页面,然后 Vue Router 会根据 URL 自动渲染对应的视图。

举例:Nginx 服务器配置

在 Nginx 中,你可以使用以下配置:

server {
  listen 80;
  server_name example.com;
  
  root /path/to/your/project/dist;
  
  location / {
    try_files $uri $uri/ /index.html;
  }
}
  • 解释
    • root /path/to/your/project/dist;:设置静态文件目录。
    • location / { try_files $uri $uri/ /index.html; }:如果用户请求的路径(如 /home)对应的文件不存在,Nginx 会返回 index.html,然后交由前端的 Vue Router 进行处理。

http://www.kler.cn/a/450148.html

相关文章:

  • webrtc获取IceCandidate流程
  • DL作业11 LSTM
  • Windows 11 安装 Dify 完整指南 非docker环境
  • js事件机制详解
  • LeetCode:1387. 将整数按权重排序(记忆化搜索 Java)
  • 贪心算法求解跳跃游戏
  • 【已解决】黑马点评项目Redis版本替换过程中误删数据库后前端显示出现的问题
  • 基于 SOME/IP 的动态服务发现与调用:原理、实现与示例全解析
  • selenium学习笔记(一)
  • 软件测试之非功能测试设计
  • 自然语言编写的prompt为啥比不上编程语言prompt高效?
  • LeetCode 209. 长度最小的子数组 (C++实现)
  • 编译libtorch时报错:NvToolsExt Could not open input file ***nvToolsExt64_1.lib
  • javaScript中slice()和splice()的用法与区别
  • 重温设计模式--职责链模式
  • Android基于Path的addRoundRect,Canvas剪切clipPath简洁的圆角矩形实现,Kotlin(1)
  • CS!GO
  • 灰度测试是什么
  • 【NLP 17、NLP的基础——分词】
  • 用套接字的UDP,TCP知道什么是HTTP吗?
  • Apache解析漏洞(apache_parsing_vulnerability靶场攻略CVE-2017-15715靶场攻略)
  • 服务平滑发布与线上验证
  • CNN、RNN、LSTM和Transformer之间的区别和联系
  • 安装CPU版的torch(清华源)
  • 经典案例PPT | 大型水果连锁集团新零售数字化建设方案
  • Ubuntu下C语言操作kafka示例