一、核心区别概览
| 特性 | 哈希模式 (hash mode) | 历史模式 (history mode) |
|---|---|---|
| URL 格式 | http://example.com/#/home |
http://example.com/home |
| 原理 | 监听 hashchange 事件 |
使用 History API (pushState/replaceState) |
| 兼容性 | IE8+ | IE10+ |
| 服务器配置 | 无需特殊配置 | 需要配置支持 |
| SEO | 不友好 | 友好(需要 SSR 配合) |
二、哈希模式 (Hash Mode)
- 实现原理
javascript
// Vue Router 内部实现简化版
class HashRouter {
constructor() {
// 1. 监听 hashchange 事件
window.addEventListener('hashchange', () => {
this.handleHashChange(window.location.hash);
});
// 2. 初始加载
window.addEventListener('load', () => {
if (!window.location.hash) {
window.location.hash = '/';
}
});
}
handleHashChange(hash) {
// 去除 # 号
const path = hash.slice(1) || '/';
// 路由匹配和渲染...
}
push(path) {
window.location.hash = path;
}
}
- 特点分析
javascript
// URL 示例
// 完整URL: https://example.com/#/user/profile
console.log(window.location);
/*
{
href: "https://example.com/#/user/profile",
hash: "#/user/profile", // 路由信息在这里
pathname: "/", // 始终是根路径
search: "", // 查询参数在hash前
hostname: "example.com"
}
*/
// 哈希变化不会触发页面刷新
// 只会触发 hashchange 事件
window.onhashchange = function(event) {
console.log('旧URL:', event.oldURL);
console.log('新URL:', event.newURL);
};
- 配置方式
javascript
// Vue Router 配置
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(), // 使用哈希历史
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
三、历史模式 (History Mode)
- 实现原理
javascript
// Vue Router 内部实现简化版
class HistoryRouter {
constructor() {
// 1. 监听 popstate 事件(浏览器前进后退)
window.addEventListener('popstate', (event) => {
this.handlePopState(event.state);
});
// 2. 拦截链接点击(阻止默认行为)
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.href) {
e.preventDefault();
this.push(e.target.getAttribute('href'));
}
});
}
push(path) {
// 使用 History API 添加记录
window.history.pushState({ path }, '', path);
// 手动触发路由更新
this.updateRoute(path);
}
replace(path) {
window.history.replaceState({ path }, '', path);
this.updateRoute(path);
}
handlePopState(state) {
this.updateRoute(state?.path || window.location.pathname);
}
}
- History API 详解
javascript
// 核心 API 方法
// 1. pushState - 添加历史记录(不会触发页面刷新)
history.pushState(state, title, url);
// 示例:
history.pushState({ page: 1 }, "Page 1", "/page1");
// 2. replaceState - 替换当前历史记录
history.replaceState(state, title, url);
// 示例:
history.replaceState({ page: 2 }, "Page 2", "/page2");
// 3. popstate 事件 - 监听前进后退
window.addEventListener('popstate', (event) => {
console.log('位置变化到:', event.state);
});
// 4. 获取当前状态
const currentState = history.state;
- 配置方式
javascript
// Vue Router 配置
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(), // 使用 HTML5 历史模式
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/:pathMatch(.*)*', component: NotFound } // 404页面
]
})
四、服务器配置差异
- 哈希模式(无需配置)
bash
# 所有请求都返回 index.html
# 哈希部分由前端处理
https://example.com/#/about → 返回 index.html
https://example.com/#/user/1 → 返回 index.html
- 历史模式(必须配置)
nginx文件
bash
# Nginx 配置示例
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html; # 关键:重定向到 index.html
}
}
apache文件
bash
# 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>
javascript文件
javascript
// Node.js Express 配置
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) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
五、优缺点对比
哈希模式
优点:
兼容性好(支持 IE8+)
无需服务器特殊配置
部署简单,适合静态托管
不会发起服务器请求(hash变化)
缺点:
URL 不美观,有 # 符号
SEO 不友好,爬虫可能忽略 hash 部分
某些锚点功能冲突
历史模式
优点:
URL 美观,无 # 符号
SEO 友好(配合 SSR 更佳)
完整的 URL 路径语义
可以利用完整的 URL 进行分享
缺点:
需要服务器支持(所有路由返回 index.html)
兼容性要求 IE10+
部署配置相对复杂