路由模式
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)匹配組件。
- 動態渲染對應組件,最終顯示你想要的頁面。
-
這就是單頁應用的核心:一個入口文件 + 前端路由動態渲染,實現 “看似多頁,實則單頁” 的體驗。