Vue进阶:vue 路由的两种模式:hash与history_vue创建中的history
Vue进阶:vue 路由的两种模式:hash与history_vue创建中的history
一、背景与问题
在单页应用(SPA)开发中,页面跳转是核心功能之一。Vue Router 作为官方路由管理器,提供了两种模式:hash 模式和 history 模式。这两种模式在底层实现和应用场景上有显著差异,理解其原理和适用场景是构建健壮应用的关键。
核心问题
- 为什么需要两种模式?
- 它们在底层是如何工作的?
- 什么场景下应该选择哪种模式?
- 实际开发中可能遇到哪些陷阱?
二、基本原理
1. hash 模式原理
hash 模式通过 URL 的 # 后缀来实现路由。浏览器会忽略 # 后的内容,因此不会触发页面刷新。通过监听 hashchange 事件,可以捕获 URL 变化并更新页面内容。
关键点:
- URL 始终带有
#前缀 - 浏览器不会向服务器发送请求
- 不需要服务器配置
2. history 模式原理
history 模式利用 HTML5 的 pushState 和 replaceState API,直接修改浏览器历史记录。URL 中不包含 #,但会触发完整的页面加载过程。需要服务器配置来支持 404 页面重定向。
关键点:
- URL 与实际路径一致
- 浏览器会向服务器发送请求
- 需要服务器配置支持
三、环境准备
1. 项目初始化
npm init -y
npm install vue vue-router@42. 基础配置
// main.js
import { createApp } from 'vue'
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import App from './App.vue'
// 路由配置
const routes = [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/about', component: () => import('./views/About.vue') }
]
// 创建路由实例
const router = createRouter({
history: createWebHistory(), // 或 createWebHashHistory()
routes
})
createApp(App).use(router).mount('#app')四、核心实现
1. hash 模式实现
// router.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
const routes = [
{ path: '/#/', component: Home },
{ path: '/#/about', component: About }
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router关键代码解释:
createWebHashHistory()创建 hash 模式实例- 路由路径以
/#/开头 - 浏览器自动处理
hashchange事件
2. history 模式实现
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router关键代码解释:
createWebHistory()创建 history 模式实例- 路由路径直接使用路径名
- 需要服务器配置支持
3. 动态路由示例
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import User from './views/User.vue'
const routes = [
{
path: '/user/:id',
component: User,
props: true // 将参数作为 props 传递
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router关键代码解释:
- 使用
:id定义动态路由参数 props: true将参数作为 props 传递给组件- 在组件中通过
this.$route.params.id获取参数
五、完整案例
1. 博客系统案例
项目结构
blog-app/
├── index.html
├── main.js
├── router.js
├── views/
│ ├── Home.vue
│ ├── PostList.vue
│ └── PostDetail.vue
└── App.vue配置文件
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import PostList from './views/PostList.vue'
import PostDetail from './views/PostDetail.vue'
const routes = [
{ path: '/', component: Home },
{
path: '/posts',
component: PostList,
children: [
{
path: 'post/:id',
component: PostDetail,
props: true
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router组件代码
<!-- Home.vue -->
<template>
<div>
<h1>博客首页</h1>
<router-link to="/posts">查看所有文章</router-link>
</div>
</template><!-- PostList.vue -->
<template>
<div>
<h2>文章列表</h2>
<ul>
<li v-for="post in posts" :key="post.id">
<router-link :to="`/posts/post/${post.id}`">{{ post.title }}</router-link>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
posts: [
{ id: 1, title: 'Vue Router 入门' },
{ id: 2, title: '深入理解 Vue 3' }
]
}
}
}
</script><!-- PostDetail.vue -->
<template>
<div>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
</div>
</template>
<script>
export default {
props: ['id'],
data() {
return {
post: {
id: this.id,
title: '默认文章',
content: '这是默认内容'
}
}
},
mounted() {
// 模拟从服务器获取数据
this.post = {
id: this.id,
title: `文章 ${this.id}`,
content: `这是文章 ${this.id} 的内容`
}
}
}
</script>六、源码解析
1. history 模式核心逻辑
// vue-router/dist/vue-router.mjs
function createWebHistory(base = '/') {
const history = {
base,
push: (path, state) => {
// 调用浏览器 API 修改历史记录
window.history.pushState(state, '', base + path)
},
replace: (path, state) => {
window.history.replaceState(state, '', base + path)
}
}
return history
}关键点:
- 使用
pushState和replaceState修改历史记录 - 需要服务器支持 404 重定向
- URL 完全匹配路由路径
2. hash 模式核心逻辑
// vue-router/dist/vue-router.mjs
function createWebHashHistory(base = '/') {
const history = {
base,
push: (path, state) => {
// 调用浏览器 API 修改 hash
window.location.hash = base + path
},
replace: (path, state) => {
window.location.replace(base + path)
}
}
return history
}关键点:
- 直接操作 URL 的
hash部分 - 不需要服务器配置
- URL 保持
#前缀
七、进阶使用
1. 动态加载组件
const routes = [
{
path: '/dynamic',
component: () => import('./views/Dynamic.vue')
}
]2. 嵌套路由
const routes = [
{
path: '/user',
component: UserLayout,
children: [
{ path: '', redirect: 'profile' },
{ path: 'profile', component: UserProfile },
{ path: 'posts', component: UserPosts }
]
}
]3. 路由守卫
const routes = [
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
if (isAuthenticated()) {
next()
} else {
next('/login')
}
}
}
]八、性能与工程实践
1. 性能优化
history 模式优化方案:
- 使用
vue-router的scrollBehavior控制滚动位置 - 启用
prefetch预加载 - 使用
vite或webpack的代码分割
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
return { top: 0 }
}
})2. 安全风险
常见风险:
- 路由参数注入
- 前端验证不足
- 跨站请求伪造(CSRF)
防护措施:
- 对所有参数进行校验
- 启用 CORS 策略
- 对敏感操作进行二次验证
3. 服务器配置
history 模式服务器配置示例(Nginx):
location / {
try_files $uri $uri/ /index.html;
}常见错误:未配置服务器导致 404 错误
九、常见问题与踩坑
1. 常见错误
错误 1:404 页面未处理
错误代码:
// 未处理 404 页面解决方法:
const routes = [
{ path: '/:pathMatch(.*)', redirect: '/' }
]错误 2:history 模式下页面刷新后空白
错误原因:服务器未正确配置
解决方法:确保服务器将所有请求重定向到 index.html
2. 常见陷阱
陷阱 1:URL 中的 # 未处理
错误代码:
// 错误处理解决方法:使用 window.location.hash 处理 hash 部分
陷阱 2:SEO 不友好
解决方案:使用 history 模式并配合服务器配置
十、最佳实践
1. 推荐方案
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| SEO 要求高 | history | URL 更友好 |
| 兼容性要求高 | hash | 无需服务器配置 |
| 单页应用 | history | 更符合 RESTful 风格 |
2. 实践建议
- 始终使用
vue-router的beforeEach守卫 - 对所有路由参数进行校验
- 使用
vite或webpack的代码分割优化性能 - 遇到 404 错误时立即处理
十一、总结
Vue 路由的 hash 和 history 模式是构建单页应用的核心技术。理解它们的原理和差异,能够帮助开发者在不同场景下做出最佳选择。hash 模式适合对兼容性要求高的场景,而 history 模式更适合需要 SEO 支持的项目。实际开发中需要注意服务器配置、性能优化和安全防护,避免常见的坑。通过合理使用路由守卫、动态加载和嵌套路由,可以构建出更加健壮和高效的单页应用。
评论已关闭