vue-router两种模式的区别
参考文献:
- https://blog.csdn.net/lla520/article/details/77894985/
- https://segmentfault.com/a/1190000015123061
- https://blog.csdn.net/bujiongdan/article/details/81429927
前后端分离常借助 Ajax,在不刷新浏览器文档的情况下完成异步数据交互。单页应用(SPA)通常只有一个 HTML 入口,不仅页面交互不刷新,页面跳转也由前端路由更新视图而不重新请求整页。
前端路由的核心是匹配 URL,加载对应组件,再动态渲染页面区域。
hash 模式
URL 中 # 后的 fragment 不会随 HTTP 请求发送给服务器。原生 hash 路由可以监听 hashchange,在 hash 改变后更新局部内容:
window.addEventListener('hashchange', (event) => {
console.log(event.oldURL, event.newURL)
const hash = location.hash.slice(1)
document.body.style.color = hash
})
上面的教学实验可通过改变 hash 改变页面字体颜色。它说明了浏览器原生机制,但当前 Vue Router 4 应使用公开 API createWebHashHistory(),不应把手写监听器当作 Router 4 的完整内部实现。

Router 3 历史实现
Vue Router 3 的 mode 会选择不同的内部 history 类。下面是历史源码片段,不是 Router 4 的公共 API:
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
assert(false, `invalid mode: ${mode}`)
}
在该历史实现中,HashHistory.push() 新增一条历史记录,HashHistory.replace() 替换当前记录。对应的栈变化如下:
下面两张历史截图标题中的
This是原图笔误,JavaScript 中应写成this;图片仅用于说明历史栈变化,正文代码以正确写法为准。
hash URL 也会被浏览器记录,因此前进和后退仍然可用,页面状态可以和 URL 对应起来。
history 模式
HTML5 History API 提供 pushState() 和 replaceState()。它们可在同源限制内修改 URL,分别新增历史条目和替换当前条目,而且不会自动重新加载页面:
window.history.pushState({ page: 1 }, '', '/page/1')
window.history.replaceState({ page: 2 }, '', '/page/2')
第二个参数是因历史原因保留的 unused,不能省略,通常传空字符串。脚本可以读取 history.length 和当前条目的 history.state,不能枚举或读取完整历史栈。
popstate 是事件,不是 popState() 方法。浏览器前进、后退,或调用 go()、back()、forward() 激活另一历史条目时通常会触发它;直接调用 pushState()、replaceState() 不会自动触发 popstate。
window.addEventListener('popstate', (event) => {
console.log(event.state)
})
history.go(-2)
history.go(2)
history.back()
history.forward()
两种模式的区别
- hash 模式只能改变
#后的 fragment;pushState()可把 URL 改为当前页面同源的任意 URL。 - fragment 不发送给服务器;history 模式的 pathname 和 query 会在真实请求(直接打开、刷新)中发送给服务器。
- hash 模式通常无需服务器路由配合;history 模式需要部署 fallback。
history 模式下刷新 /user/id 会真实请求该地址。服务器应将未命中后端接口和静态资源的前端路由请求 rewrite/fallback 到同一份 index.html,并保持地址不变;这不是把浏览器绝对重定向到根路径。应用内还应配置 catch-all 404,否则任何未知地址都可能得到 index.html。
当前 Vue Router 4 写法
Router 4 不再使用 new VueRouter({ mode }),而是在创建时显式传入 history 工厂:
import {
createMemoryHistory,
createRouter,
createWebHashHistory,
createWebHistory
} from 'vue-router'
const router = createRouter({
history: createWebHistory(),
// 也可使用 createWebHashHistory();SSR/无浏览器 URL 场景可用 createMemoryHistory()
routes
})
程序化导航使用公开的 Router 实例方法:
await router.push({ name: 'user', params: { id: '42' } })
await router.replace('/login')
router.go(-1)
router.back()
router.forward()
push() 与 replace() 返回 Promise,导航可能被守卫取消、被新导航取代或因重复导航而失败;需要时应 await 并结合 isNavigationFailure() 检查结果。
$router 与 $route
Vue 2 + Router 3 历史写法是在根实例注入 router:
new Vue({ router }).$mount('#app')
当时常用 this.$router 表示 Router 实例,用 this.$route 读取当前路由的 name、path、query、params 等。this.$options.router 属于旧版插件实现细节,不应作为当前判断根组件的公共规则。
Router 4 的 Options API 组件仍可使用 $router、$route;Composition API 推荐:
const router = useRouter()
const route = useRoute()
await router.push({ name: 'user', params: { id: route.params.id } })
route 是响应式对象,通常只监听所需字段,而不是监听整个 route。

