Vue的路由模式的区别和原理
路由模式
Vue 的路由模式指的是 Vue Router 提供的 URL 处理方式
,主要有两种:Hash 模式和History 模式。
Hash模式
在 Vue Router 中,默认使用的是 hash 模式,即 mode: 'hash'
。如果想要使用 history 模式,可以设置 mode: 'history'
。
原理
-
Hash 模式基于浏览器的
window.location.hash
属性。当 URL 中的哈希部分发生变化时,Vue Router 会监听到这个变化,并相应地切换视图。 -
Hash 模式
不会向服务器发送请求
。这是因为 URL 中的哈希值(# 后面的部分)的变化不会触发浏览器重新加载页面或向服务器发送新请求
核心原理
-
哈希值变化:当 URL 的哈希部分(如 http://example.com/#/home 中的 /home)发生变化时,浏览器只会:
更新 window.location.hash
属性。触发 hashchange
事件(可通过window.addEventListener
(hashchange
, callback) 监听)。
-
Vue Router 的处理:Vue Router 监听
hashchange
事件,根据新的哈希值匹配对应的路由配置
,然后动态更新组件视图。整个过程完全在前端完成,不会向服务器发送任何请求 -
下面是Vue3底层hash改变的代码实现(有兴趣可以看一下)
// 简化版 Vue Router 核心实现
class Router {constructor(options) {this.routes = options.routes || [];this.currentPath = window.location.hash.slice(1) || '/';// 创建响应式数据:使用 Vue 3 的 reactive 原理(简化版)this.currentRoute = this.createReactive({path: this.currentPath,component: null});// 初始化路由监听this.init();}// 创建简易响应式对象(模拟 Vue 3 的 Proxy 实现)createReactive(target) {return new Proxy(target, {set: (obj, key, value) => {obj[key] = value;this.updateView(); // 值变化时更新视图return true;}});}// 初始化路由监听init() {// 1. 初始加载时处理当前哈希值this.handleHashChange();// 2. 监听哈希值变化window.addEventListener('hashchange', () => {this.handleHashChange();});}// 处理哈希值变化handleHashChange() {this.currentPath = window.location.hash.slice(1) || '/';this.matchRoute();}// 匹配路由matchRoute() {const route = this.routes.find(route => {// 简化的路径匹配(实际 Vue Router 使用更复杂的路径解析)return route.path === this.currentPath;});if (route) {this.currentRoute.path = route.path;this.currentRoute.component = route.component;} else {// 处理 404 路由this.currentRoute.path = '*';this.currentRoute.component = this.routes.find(r => r.path === '*')?.component;}}// 更新视图(模拟 Vue 的虚拟 DOM 更新)updateView() {// 在实际 Vue Router 中,这里会触发 Vue 组件的重新渲染console.log(`路由变更为: ${this.currentRoute.path}`);}
}// 模拟 Vue 组件系统
function createComponent(options) {return {...options,render() {// 实际 Vue 会根据模板生成 VNode 并渲染console.log(`渲染组件: ${this.name}`);}};
}// 使用示例
const HomeComponent = createComponent({name: 'Home',template: '<div>Home Page</div>'
});const AboutComponent = createComponent({name: 'About',template: '<div>About Page</div>'
});const router = new Router({routes: [{ path: '/', component: HomeComponent },{ path: '/about', component: AboutComponent },{ path: '*', component: createComponent({ name: 'NotFound', template: '<div>404 Not Found</div>' }) }]
});// 模拟路由切换
window.setTimeout(() => {window.location.hash = '/about';
}, 2000);
Vue2设置Hash模式
import Vue from 'vue';
import VueRouter from 'vue-router';Vue.use(VueRouter);const routes = [// 路由配置
];const router = new VueRouter({mode: 'hash', // 使用 hash 模式routes
});new Vue({router,render: h => h(App)
}).$mount('#app');
Vue3设置Hash模式
import { createRouter, createWebHashHistory } from 'vue-router';// 导入组件
import Home from '../views/Home.vue';
import About from '../views/About.vue';// 定义路由
const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',component: About}
];// 创建路由实例并配置 hash 模式
const router = createRouter({history: createWebHashHistory(), // 指定为 hash 模式routes
});export default router;
优势
- 兼容性: Hash 模式在不同浏览器之间的兼容性较好,因为浏览器对于哈希部分的处理方式基本一致。
- 无需服务器支持: 不需要后端服务器的特殊配置,可以在任意静态服务器上使用。
缺点
- URL 美观度: URL 中带有 # 符号,可能不够美观。
- SEO 不友好: 对搜索引擎的优化相对较差,因为搜索引擎不会将哈希部分的内容作为独立的页面来处理。
History模式
原理
在 Vue Router 中,History 模式基于 HTML5 的 History API
实现,通过操作浏览器的历史记录栈
,在不刷新页面的情况下改变 URL
,同时还能实现前进、后退等导航功能
https://www.doubao.com/thread/wa13961c844859854
- NodeJs的配置实现
const http = require('http')
const fs = require('fs')
const httpPort = 80http.createServer((req, res) => {fs.readFile('index.html', 'utf-8', (err, content) => {if (err) {console.log('We cannot open "index.html" file.')}res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'})res.end(content)})
}).listen(httpPort, () => {console.log('Server listening on: http://localhost:%s', httpPort)
})
特点
- History 模式下的路由切换操作(如 pushState)本身确实不需要向后端发送请求
- 当用户直接访问 / 刷新子路由(如 http://example.com/about)时,浏览器会主动向后端发送请求,这才是需要后端配置的原因。
正常路由切换(通过 pushState
)
用户在页面内点击按钮触发 router.push('/about')
时:
- 前端调用
history.pushState()
,URL 变为 http://example.com/about(不刷新页面)。 - 前端路由匹配 /about,渲染 About 组件(纯前端操作,无需后端参与)。
直接访问 / 刷新子路由(如输入 http://example.com/about
回车)
当用户直接在地址栏输入 http://example.com/about 并回车,或在该页面按 F5 刷新时:
-
浏览器会认为这是一个全新的 HTTP 请求,按照 URL 的路径(/about)向服务器发送请求。
-
服务器默认会找 /about 对应的物理文件,但前端路由是单页应用(只有 index.html),所以服务器找不到资源,返回 404。
-
后端配置(如 Nginx 的 try_files、Express 的 * 路由)的核心逻辑是:
无论请求的路径是什么(如 /about、/user),都返回前端的 index.html。-
这样,当用户直接访问 / 刷新子路由时:
-
服务器返回 index.html → 浏览器加载 HTML 和 JS。
-
前端路由启动,读取当前 URL(/about),匹配并渲染组件。
-
为什么 Hash 模式不需要处理这种情况
-
Hash 模式的 URL 是 http://example.com/#/about,浏览器在发送请求时,只会把 # 前面的部分(http://example.com/)发给服务器,所以服务器始终返回 index.html,前端路由能正常运行。
-
而 History 模式的 URL 是 http://example.com/about(无 #),浏览器会把完整路径 /about 发给服务器,导致需要后端干预。
Vue3配置History模式
import { createRouter, createWebHistory } from 'vue-router'// 创建路由
const router = createRouter({history: createWebHistory(),// routes: routes 的缩写routes,
})
优势
- URL 美观度: URL 更加美观,不带有 # 符号。
- SEO 友好: 对搜索引擎的优化更好,因为搜索引擎能够更好地处理没有哈希部分的 URL。
缺点
- 兼容性: 兼容性相对较差,需要服务器的支持,且在某些环境中可能需要额外的配置。
- 需要服务器支持: 刷新页面或直接访问某个路由时,服务器需要正确处理这个路由。
总结
-
History 模式的路由切换本身(pushState)不需要后端参与,但
“直接访问 / 刷新子路由”` 的场景会触发浏览器向后端发送请求,因此需要后端配置兜底规则(返回 index.html)。 -
服务器返回 index.html 后,前端路由会接管 URL 解析和组件渲染:
- index.html 加载前端框架和路由逻辑。
- 前端路由根据当前 URL(/about)匹配组件。
- 动态渲染对应组件,最终显示你想要的页面。
-
这就是单页应用的核心:一个入口文件 + 前端路由动态渲染,实现 “看似多页,实则单页” 的体验。