在 vue-router 中,路由模式决定了 URL 的表现形式和页面导航的实现逻辑。目前 vue-router 支持两种核心路由模式:hash 模式(默认)和history 模式,两者在 URL 格式、底层原理、兼容性和部署要求上存在显著差异。

本文将从 “实现原理”“核心差异”“适用场景” 三个维度,全面解析两种模式的区别,帮你在项目开发中做出正确选择。

一、先明确:两种模式的本质区别

hash 模式和 history 模式的核心目标一致 —— 实现 “单页应用(SPA)的无刷新导航”,但实现方式完全不同:

  • hash 模式:基于 URL 中的 “哈希值”(#及其后面的内容)实现,通过监听哈希值变化触发页面更新;

  • history 模式:基于 HTML5 的History APIpushStatereplaceState)实现,通过操作浏览器历史记录实现无刷新导航,URL 中无#

二、底层实现原理拆解

要理解两种模式的差异,首先需要掌握它们的底层实现逻辑 —— 这是后续所有差异的根源。

1. hash 模式:依赖 URL 哈希值的 “锚点特性”

(1)哈希值的核心特性

URL 中的#(哈希符)后面的部分称为 “哈希值”(如https://xxx.com/#/home中的/home),它有两个关键特性:

  1. 哈希值变化不会触发页面刷新:当修改 URL 中的哈希值时,浏览器只会更新地址栏的 URL,不会向服务器发送新的 HTTP 请求,因此页面不会刷新;

  2. 哈希值变化会触发hashchange事件:浏览器提供了window.onhashchange事件,当哈希值变化时,可通过该事件监听并执行自定义逻辑(如更新页面内容)。

(2)hash 模式的实现流程

vue-router 的 hash 模式正是利用了哈希值的这两个特性,实现无刷新导航:

  1. 初始化路由:当应用加载时,vue-router 解析 URL 中的哈希值(如#/home),匹配对应的路由规则,渲染对应的组件;

  2. 监听哈希变化:通过window.addEventListener('hashchange', handler)监听哈希值变化;

  3. 导航触发:当用户点击<router-link to="/about">时,vue-router 不会触发页面跳转,而是修改 URL 的哈希值(如从#/home改为#/about);

  4. 更新视图:哈希值变化触发hashchange事件,vue-router 在事件回调中解析新的哈希值,匹配路由并更新页面组件(无刷新)。

(3)示例 URL

hash 模式的 URL 格式:https://yourdomain.com/#/homehttps://yourdomain.com/#/user/123,URL 中始终包含#

2. history 模式:依赖 HTML5 的 History API

(1)History API 的核心能力

HTML5 新增的History API为浏览器历史记录提供了更灵活的操作方式,核心是两个方法:

  • history.pushState(state, title, url):向浏览器历史记录中 “添加一条新记录”,修改地址栏 URL,但不发送 HTTP 请求,也不触发页面刷新;

  • history.replaceState(state, title, url):“替换当前的历史记录”,同样不发送 HTTP 请求,仅修改地址栏 URL;

  • 两者的区别:pushState会增加一条历史记录(可通过 “后退” 按钮返回上一页),replaceState会覆盖当前历史记录(无法通过 “后退” 返回修改前的 URL)。

(2)history 模式的实现流程

vue-router 的 history 模式通过History API实现无刷新导航,流程如下:

  1. 初始化路由:应用加载时,vue-router 解析当前 URL(如https://yourdomain.com/home),匹配路由规则并渲染组件;

  2. 监听历史变化:通过window.addEventListener('popstate', handler)监听浏览器的 “前进 / 后退” 按钮事件(popstate事件仅在点击前进 / 后退或调用history.back()/history.forward()时触发,pushState/replaceState不会触发);

  3. 导航触发:用户点击<router-link to="/about">时,vue-router 调用history.pushState(null, null, '/about'),修改地址栏 URL 为https://yourdomain.com/about,不发送 HTTP 请求;

  4. 更新视图:手动调用路由匹配逻辑,根据新 URL 渲染对应的组件(无刷新);

  5. 处理前进 / 后退:当用户点击浏览器 “后退” 按钮时,触发popstate事件,vue-router 解析当前 URL,更新视图。

(3)示例 URL

history 模式的 URL 格式:https://yourdomain.com/homehttps://yourdomain.com/user/123,URL 与传统后端路由格式一致,无#

三、核心差异对比(7 大维度)

为了更直观地理解两种模式的区别,我们从 URL 表现、兼容性、部署要求等 7 个核心维度进行对比:

对比维度 hash 模式 history 模式
URL 格式 包含#(如https://xxx.com/#/home #(如https://xxx.com/home),URL 更美观
底层原理 依赖 URL 哈希值的hashchange事件 依赖 HTML5 的History APIpushState/replaceState
兼容性 支持所有浏览器(包括 IE8 及以下) 仅支持 HTML5 兼容的浏览器(IE10 及以上)
后端依赖 无:刷新页面时,浏览器仅向服务器请求https://xxx.com/(哈希值不会发送到服务器) 有:刷新页面时,浏览器会向服务器请求https://xxx.com/home,需后端配置 “所有路由指向 index.html”,否则返回 404
锚点功能 无法使用原生锚点(#已被路由占用),需自定义锚点逻辑 支持原生锚点(如https://xxx.com/home#section1
历史记录操作 仅能通过哈希值变化管理历史,灵活性低 可通过pushState/replaceState灵活操作历史记录,支持自定义状态数据
SEO 友好性 略差:部分搜索引擎可能忽略#后的内容 更好:URL 与传统路由一致,搜索引擎更易识别(需配合后端 SSR 或静态生成优化)

四、部署要求:history 模式需后端配置(关键!)

两种模式的部署差异是项目开发中最容易踩坑的点,尤其是 history 模式 —— 若后端未正确配置,会导致 “刷新页面返回 404” 的问题。

1. hash 模式的部署:无需特殊配置

hash 模式下,无论用户访问https://xxx.com/#/home还是https://xxx.com/#/user/123,当页面刷新时,浏览器只会向服务器发送https://xxx.com/的请求(哈希值#/home不会被发送到服务器)。因此,只需将前端打包后的文件(如index.htmlcssjs)部署到服务器的根目录,无需任何后端配置,刷新页面不会出现 404。

2. history 模式的部署:必须配置后端

history 模式下,当用户访问https://xxx.com/home并刷新页面时,浏览器会向服务器发送GET /home的请求 —— 若后端未配置 “/home路由指向index.html”,则服务器会返回 404 错误。

因此,history 模式部署时,需后端做 “所有路由指向前端入口文件(如index.html)” 的配置,让前端 vue-router 接管路由匹配。以下是常见后端的配置示例:

(1)Nginx 配置

nginx.conf或站点配置文件中,添加try_files指令,将所有请求转发到index.html

server {

   listen 80;

   server_name yourdomain.com; # 你的域名

   root /usr/share/nginx/html; # 前端打包文件的根目录

   index index.html; # 入口文件

   # 关键配置:所有请求都转发到index.html

   location / {

       try_files $uri $uri/ /index.html;

   }

}
(2)Apache 配置

在项目根目录创建.htaccess文件,添加以下规则:

<IfModule mod_rewrite.c>

 RewriteEngine On

 RewriteBase /

 RewriteRule ^index\.html$ - [L]

 RewriteCond %{REQUEST_FILENAME} !-f

 RewriteCond %{REQUEST_FILENAME} !-d

 RewriteRule . /index.html [L]

</IfModule>
(3)Node.js(Express)配置

在 Express 项目中,使用express-history-api-fallback中间件:

const express = require('express');

const history = require('express-history-api-fallback');

const app = express();

const root = __dirname + '/public'; // 前端打包文件目录

app.use(express.static(root));

app.use(history('index.html', { root: root })); // 所有请求转发到index.html

app.listen(3000, () => {

 console.log('Server running on port 3000');

});

五、选型建议:如何选择适合的模式?

两种模式没有绝对的 “优劣”,选择的核心是 “项目需求” 和 “技术环境”,以下是具体的选型建议:

1. 优先选择 hash 模式的场景

  • 兼容性要求高:项目需要支持 IE8 及以下浏览器(如面向政府、企业的老旧系统);

  • 快速部署:无后端开发团队支持,或后端无法配合配置(如静态站点部署到 GitHub Pages,默认不支持 history 模式的后端配置);

  • 简单需求:项目无需美观的 URL,仅需实现基础的 SPA 导航功能。

2. 优先选择 history 模式的场景

  • URL 美观需求:项目对 URL 格式有要求(如官网、移动端应用),需要去掉#,提升用户体验;

  • 锚点功能需求:项目需要使用原生锚点(如长页面导航到指定章节);

  • SEO 优化需求:项目需要更好的 SEO 表现(配合 SSR 或静态生成,如 Nuxt.js 项目);

  • 技术环境允许:后端团队可配合配置路由转发,且目标浏览器支持 HTML5(IE10 及以上,现代浏览器均支持)。

六、常见问题与解决方案

1. history 模式刷新页面 404?

原因:刷新时浏览器向服务器请求具体路由(如/home),后端未配置转发到index.html

解决方案:按上文 “history 模式的部署” 配置后端(Nginx/Apache/Node.js),将所有路由指向index.html

2. hash 模式如何实现锚点功能?

原因#已被路由占用,原生锚点(如#section1)会被解析为路由;

解决方案:自定义锚点逻辑,通过scrollTo或第三方库(如vue-scrollto)实现页面滚动到指定位置。

3. 如何在 vue-router 中切换模式?

在创建 vue-router 实例时,通过mode选项指定模式:

// router/index.js

import Vue from 'vue';

import Router from 'vue-router';

import Home from '@/views/Home';

Vue.use(Router);

export default new Router({

 mode: 'hash', // 可选值:'hash'(默认)或 'history'

 routes: [

   { path: '/', name: 'Home', component: Home }

 ]

});

七、总结

hash 模式和 history 模式是 vue-router 实现 SPA 无刷新导航的两种核心方式,核心差异源于底层实现原理:

  • hash 模式:兼容性强、无需后端配置,但 URL 含#,美观度和功能灵活性较低;

  • history 模式:URL 美观、支持原生锚点和 SEO 优化,但依赖 HTML5、需后端配置,兼容性稍弱。

在实际项目中,若后端可配合配置且无需支持老旧浏览器,优先选择 history 模式;若需兼容 IE8 及以下或无后端支持,选择 hash 模式即可。理解两种模式的原理和差异,能帮助我们在项目开发中避免部署错误,提升用户体验。

更多推荐