库库鲁嘎嘣脆 發表於 2026-1-5 10:06:59

Vue Router 中 Hash和 History 模式的核心区别、使用场景

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、先搞懂:前端路由的核心本质</a></li><li><a href="#_label1">二、Hash 模式(哈希模式)</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">1. 核心定义</a></li><li><a href="#_lab2_1_1">2. 底层实现原理</a></li><ul class="third_class_ul"><li><a href="#_label3_1_1_0">(1)核心 API:window.onhashchange</a></li><li><a href="#_label3_1_1_1">(2)路由跳转的本质</a></li></ul><li><a href="#_lab2_1_2">3. Vue Router 中配置 Hash 模式</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_1_3">4. 核心特点(优缺点)</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label2">三、History 模式(HTML5 历史模式)</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_4">1. 核心定义</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_2_5">2. 底层实现原理</a></li><ul class="third_class_ul"><li><a href="#_label3_2_5_2">(1)核心 API:HTML5 History API</a></li><li><a href="#_label3_2_5_3">(2)路由跳转的本质</a></li></ul><li><a href="#_lab2_2_6">3. Vue Router 中配置 History 模式</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_2_7">4. 核心特点(优缺点)</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label3">四、Hash 模式 vs History 模式 核心对比表</a></li><ul class="second_class_ul"></ul><li><a href="#_label4">五、实战部署:History 模式解决 404 的核心方案</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_8">1. Nginx 配置(最常用,你的场景)</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_4_9">2. Apache 配置</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_4_10">3. Node.js Express 配置</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label5">六、选型建议:什么时候用 Hash/History?</a></li><ul class="second_class_ul"><li><a href="#_lab2_5_11">选 Hash 模式的场景</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_5_12">选 History 模式的场景</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label6">七、常见问题 &amp; 解决方案</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_13">1. History 模式刷新 404</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_6_14">2. Hash 模式 URL 中的 # 影响锚点</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_6_15">3. History 模式部署在子路径(如/vue3-app)</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_6_16">总结(核心关键点)</a></li><ul class="third_class_ul"></ul></ul></ul></div><p>深入理解 Vue Router 中 <strong>Hash 模式</strong> 和 <strong>History 模式</strong> 的核心区别、底层原理、使用场景及部署注意事项,我会从「本质&rarr;原理&rarr;实战&rarr;对比&rarr;问题解决」全维度超详细讲解,结合你的项目场景(比如之前部署 History 模式报 404)帮你彻底吃透。</p>
<p class="maodian"><a name="_label0"></a></p><h2>一、先搞懂:前端路由的核心本质</h2>
<p>Vue 是单页应用(SPA),整个项目只有一个 <code>index.html</code> 文件。<strong>前端路由的核心目的</strong>:通过 JavaScript 监听 URL 变化,不刷新页面的前提下,动态渲染不同的组件,模拟 &ldquo;多页面跳转&rdquo; 的体验(无需向后端发起新的页面请求)。</p>
<p>Hash 模式和 History 模式是实现前端路由的两种技术方案,核心差异在于「URL 表现形式」「底层实现原理」「服务器部署要求」。</p>
<p class="maodian"><a name="_label1"></a></p><h2>二、Hash 模式(哈希模式)</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><p class="maodian"><a name="_lab2_2_4"></a></p><h3>1. 核心定义</h3>
<p>Hash 模式是利用 URL 中 <code>#</code> 后面的「哈希值」实现路由跳转,<code>#</code> 是浏览器的锚点标识,<strong>哈希值不会被发送到服务器</strong>。</p>
<ul><li>示例 URL:<code>http://yourdomain.com/#/proOrder</code></li><li>其中 <code>#/proOrder</code> 就是哈希路由,<code>#</code> 后面的内容完全由前端控制。</li></ul>
<p class="maodian"><a name="_lab2_1_1"></a></p><p class="maodian"><a name="_lab2_2_5"></a></p><h3>2. 底层实现原理</h3>
<p class="maodian"><a name="_label3_1_1_0"></a></p><h4>(1)核心 API:window.onhashchange</h4>
<p>浏览器天生支持监听 <code>#</code> 后面内容的变化,触发 <code>hashchange</code> 事件,前端可在该事件中判断哈希值,渲染对应组件:</p>
<div class="jb51code"><pre class="brush:js;">// 原生 JS 模拟 Hash 路由核心逻辑
window.addEventListener('hashchange', () =&gt; {
// 获取当前哈希值(去掉 #)
const hash = window.location.hash.slice(1);
// 根据哈希值渲染不同组件
if (hash === '/proOrder') {
    renderProOrderComponent();
} else if (hash === '/home') {
    renderHomeComponent();
}
});</pre></div>
<p class="maodian"><a name="_label3_1_1_1"></a></p><p class="maodian"><a name="_label3_2_5_3"></a></p><h4>(2)路由跳转的本质</h4>
<ul><li>点击 <code>&lt;router-link to=&quot;/proOrder&quot;&gt;</code> 时,Vue Router 会修改 <code>window.location.hash = &#39;#/proOrder&#39;</code>;</li><li>该操作只会改变 URL 的哈希部分,<strong>不会触发浏览器的页面刷新</strong>,也不会向服务器发请求。</li></ul>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>3. Vue Router 中配置 Hash 模式</h3>
<div class="jb51code"><pre class="brush:js;">// router/index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [/* 你的路由规则 */];
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL), // 核心:Hash 模式
routes
});
export default router;</pre></div>
<p class="maodian"><a name="_lab2_1_3"></a></p><p class="maodian"><a name="_lab2_2_7"></a></p><h3>4. 核心特点(优缺点)</h3>
<table><thead><tr><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>1. <strong>无需后端配置</strong>:哈希值不发服务器,直接访问 <code>http://xxx.com/#/proOrder</code> 不会 404;2. <strong>兼容性极好</strong>:支持所有浏览器(包括 IE6/7/8);3. <strong>开发便捷</strong>:本地 / 线上部署无需协调后端;</td><td>1. <strong>URL 不美观</strong>:带 <code>#</code> 符号,用户体验略差;2. <strong>SEO 不友好</strong>:部分搜索引擎爬虫会忽略 <code>#</code> 后的内容,影响页面收录;3. <strong>锚点冲突</strong>:若页面内有原生锚点(如 <code>&lt;a href=&quot;#top&quot;&gt;</code>),会和路由哈希冲突;</td></tr></tbody></table>
<p class="maodian"><a name="_label2"></a></p><h2>三、History 模式(HTML5 历史模式)</h2>
<h3>1. 核心定义</h3>
<p>History 模式基于 HTML5 新增的 <code>History API</code> 实现,URL 无 <code>#</code>,和传统后端路由的 URL 格式一致,<strong>哈希值会被完整发送到服务器</strong>。</p>
<ul><li>示例 URL:<code>http://yourdomain.com/proOrder</code>(和后端路由格式完全一致)</li><li>该模式是现代前端项目的主流选择(追求 URL 美观、SEO 友好)。</li></ul>
<h3>2. 底层实现原理</h3>
<p class="maodian"><a name="_label3_2_5_2"></a></p><h4>(1)核心 API:HTML5 History API</h4>
<ul><li><code>history.pushState(state, title, url)</code>:修改 URL 且不发送请求,添加一条历史记录;</li><li><code>history.replaceState(state, title, url)</code>:修改 URL 且不发送请求,替换当前历史记录;</li><li><code>window.onpopstate</code>:监听浏览器的「回退 / 前进」按钮,触发状态变化。</li></ul>
<h4>(2)路由跳转的本质</h4>
<div class="jb51code"><pre class="brush:js;">// 原生 JS 模拟 History 路由核心逻辑
// 点击跳转按钮时
document.querySelector('#toProOrder').addEventListener('click', (e) =&gt; {
e.preventDefault(); // 阻止默认a标签跳转
// 修改 URL 为 /proOrder,不发请求
history.pushState({}, '', '/proOrder');
// 手动渲染对应组件
renderProOrderComponent();
});
// 监听回退/前进
window.addEventListener('popstate', () =&gt; {
const path = window.location.pathname;
if (path === '/proOrder') {
    renderProOrderComponent();
}
});</pre></div>
<p>⚠️ 关键:<code>pushState</code> 只是修改 URL,不会触发页面刷新,但<strong>直接访问 / 刷新 <code>http://xxx.com/proOrder</code> 时,浏览器会向服务器发送该路径的请求</strong>&mdash;&mdash; 这也是你之前部署报 404 的核心原因!</p>
<p class="maodian"><a name="_lab2_2_6"></a></p><h3>3. Vue Router 中配置 History 模式</h3>
<div class="jb51code"><pre class="brush:js;">// router/index.ts(你的原有配置)
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [/* 你的路由规则 */];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), // 核心:History 模式
routes
});
export default router;</pre></div>
<h3>4. 核心特点(优缺点)</h3>
<table><thead><tr><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>1. <strong>URL 美观</strong>:无 <code>#</code>,符合用户对 URL 的认知习惯;2. <strong>SEO 友好</strong>:完整 URL 会被搜索引擎收录,利于网站优化;3. <strong>无锚点冲突</strong>:和页面内原生锚点(如 <code>#top</code>)互不干扰;</td><td>1. <strong>需要后端配置</strong>:直接访问子路由(如 <code>/proOrder</code>)会触发服务器请求,服务器未配置时返回 404;2. <strong>兼容性一般</strong>:仅支持 IE10+ 及现代浏览器;3. <strong>部署成本高</strong>:需协调后端修改 Nginx/Apache 配置;</td></tr></tbody></table>
<p class="maodian"><a name="_label3"></a></p><h2>四、Hash 模式 vs History 模式 核心对比表</h2>
<table><thead><tr><th>对比维度</th><th>Hash 模式</th><th>History 模式</th></tr></thead><tbody><tr><td>URL 格式</td><td><code>http://xxx.com/#/proOrder</code>(带 #)</td><td><code>http://xxx.com/proOrder</code>(无 #)</td></tr><tr><td>底层原理</td><td>监听 <code>window.onhashchange</code> 事件</td><td>基于 HTML5 <code>history.pushState/replaceState</code> + <code>popstate</code> 事件</td></tr><tr><td>服务器请求</td><td><code>#</code> 后的内容不发送到服务器,仅请求 <code>index.html</code></td><td>完整 URL 发送到服务器,请求 <code>/proOrder</code> 路径</td></tr><tr><td>部署要求</td><td>无需后端配置,直接部署即可</td><td>必须配置后端(Nginx/Apache),将所有路由转发到 <code>index.html</code></td></tr><tr><td>兼容性</td><td>全浏览器兼容(IE6+)</td><td>仅支持 IE10+ 及现代浏览器</td></tr><tr><td>SEO 友好性</td><td>差(爬虫忽略 # 后内容)</td><td>优(完整 URL 被收录)</td></tr><tr><td>锚点冲突</td><td>易和页面内锚点(#top)冲突</td><td>无冲突</td></tr><tr><td>历史记录</td><td>基于浏览器哈希历史,自动记录</td><td>基于 HTML5 History API,可自定义历史记录</td></tr></tbody></table>
<p class="maodian"><a name="_label4"></a></p><h2>五、实战部署:History 模式解决 404 的核心方案</h2>
<p>部署 History 模式报 404,本质是 Nginx 未配置「路由转发」,以下是不同后端的配置方案:</p>
<p class="maodian"><a name="_lab2_4_8"></a></p><h3>1. Nginx 配置(最常用,你的场景)</h3>
<div class="jb51code"><pre class="brush:js;">server {
    listen 80;
    server_name 你的域名/服务器IP;
    root /usr/share/nginx/html/你的项目dist目录; # 项目打包后的根目录
    index index.html index.htm;
    # 核心:所有请求转发到 index.html,由前端路由接管
    location / {
      try_files $uri $uri/ /index.html; # 先找物理文件→找不到就转发到index.html
      add_header Cache-Control "no-cache, no-store, must-revalidate"; # 避免缓存
    }
    # 静态资源缓存(可选,提升加载速度)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
      expires 7d;
      add_header Cache-Control "public, max-age=604800";
    }
}</pre></div>
<p class="maodian"><a name="_lab2_4_9"></a></p><h3>2. Apache 配置</h3>
<p>修改 <code>.htaccess</code> 文件(放在项目根目录):</p>
<div class="jb51code"><pre class="brush:js;">&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ -
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html
&lt;/IfModule&gt;
</pre></div>
<p class="maodian"><a name="_lab2_4_10"></a></p><h3>3. Node.js Express 配置</h3>
<div class="jb51code"><pre class="brush:js;">const express = require('express');
const path = require('path');
const app = express();
// 静态文件目录
app.use(express.static(path.join(__dirname, 'dist')));
// 所有路由转发到 index.html
app.get('*', (req, res) =&gt; {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.listen(3000, () =&gt; {
console.log('服务器运行在 3000 端口');
});</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>六、选型建议:什么时候用 Hash/History?</h2>
<p class="maodian"><a name="_lab2_5_11"></a></p><h3>选 Hash 模式的场景</h3>
<ol><li>内部管理系统(如你的工单系统)、无需 SEO 的项目;</li><li>快速开发、无法协调后端配置服务器;</li><li>需要兼容低版本浏览器(如 IE8 及以下);</li><li>临时部署、测试环境(无需复杂配置)。</li></ol>
<p class="maodian"><a name="_lab2_5_12"></a></p><h3>选 History 模式的场景</h3>
<ol><li>对外展示的官网、需要 SEO 优化的项目;</li><li>追求 URL 美观,提升用户体验;</li><li>团队能协调后端修改 Nginx/Apache 配置;</li><li>现代浏览器环境(无需兼容低版本 IE)。</li></ol>
<p class="maodian"><a name="_label6"></a></p><h2>七、常见问题 &amp; 解决方案</h2>
<p class="maodian"><a name="_lab2_6_13"></a></p><h3>1. History 模式刷新 404</h3>
<ul><li>原因:服务器未配置路由转发,直接请求 <code>/proOrder</code> 时找不到对应文件;</li><li>解决:按上文配置 Nginx/Apache,添加 <code>try_files</code>(Nginx)或 Rewrite 规则(Apache)。</li></ul>
<p class="maodian"><a name="_lab2_6_14"></a></p><h3>2. Hash 模式 URL 中的 # 影响锚点</h3>
<p>问题:页面内 <code>&lt;a href=&quot;#top&quot;&gt;回到顶部&lt;/a&gt;</code> 会被路由拦截;</p>
<p>解决:Vue Router 可配置<code>hashPrefix</code>自定义哈希前缀(如<code>#!</code>):</p>
<div class="jb51code"><pre class="brush:js;">const router = createRouter({
history: createWebHashHistory({ hashPrefix: '!' }), // 哈希前缀改为 #!
routes
});
</pre></div>
<p>此时 URL 为<code>http://xxx.com/#!/proOrder</code>,原生锚点<code>#top</code>不会冲突。</p>
<p class="maodian"><a name="_lab2_6_15"></a></p><h3>3. History 模式部署在子路径(如/vue3-app)</h3>
<ul><li>问题:部署在 <code>http://xxx.com/vue3-app/proOrder</code> 时路由失效;</li><li>解决:<ol><li>Vite 配置 <code>base: &#39;/vue3-app/&#39;</code>;</li><li>路由配置 <code>createWebHistory(import.meta.env.BASE_URL)</code>;</li><li>Nginx 配置 <code>root /usr/share/nginx/html/vue3-app;</code> + <code>try_files $uri $uri/ /vue3-app/index.html;</code>。</li></ol></li></ul>
<p class="maodian"><a name="_lab2_6_16"></a></p><h3>总结(核心关键点)</h3>
<ol><li><strong>Hash 模式</strong>:靠 <code>#</code> 分隔,无需后端配置,兼容性好,URL 带 #,SEO 差;</li><li><strong>History 模式</strong>:基于 HTML5 API,URL 美观,SEO 好,但需后端配置路由转发,否则 404;</li><li>选型核心:对内系统 / 快速开发用 Hash,对外网站 / 需 SEO 用 History;</li><li>你的项目(工单系统):若无需 SEO,用 Hash 模式可避免 Nginx 配置;若追求 URL 美观,按上文配置 Nginx 即可解决 404。</li></ol>
頁: [1]
查看完整版本: Vue Router 中 Hash和 History 模式的核心区别、使用场景