技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTVUE

vue-router两种模式的区别

所属馆藏
Vue
文件格式
Markdown
原始路径
Vue/20-vue-router两种模式的区别
本文目录4 个章节
  1. hash 模式
  2. history 模式
  3. 当前 Vue Router 4 写法
  4. 官方参考

vue-router两种模式的区别

参考文献:

前后端分离常借助 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 的 mode 与 history 实现对照

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;图片仅用于说明历史栈变化,正文代码以正确写法为准。

push 新增历史记录(历史截图,this.$router.push)

replace 替换当前历史记录(历史截图,this.$router.replace)

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 读取当前路由的 namepathqueryparams 等。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。

官方参考

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS