Vue开发中,在实现单页面应用(SPA)前端路由时的hash模式和history模式的区别及详细介绍

简介: Vue开发中,在实现单页面应用(SPA)前端路由时的hash模式和history模式的区别及详细介绍
一、前言

单页面应用(SPA)的核心思想之一,就是更新视图而不重新请求页面,简单来说,它在加载页面时,不会加载整个页面,只会更新某个指定的容器中的内容。对于大多数单页面应用,都推荐使用官方支持的vue-router。

在实现单页面前端路由时,提供了两种方式,分别是hash模式和history模式,根据mode参数来决定采用哪一种方式。

const router = new VueRouter({
  routes,
  mode: "history" // 或者 "hash"
})


二、hash模式

http://example.com/#/home

Hash模式是Vue.js中默认的URL管理模式。在Hash模式下,URL中的#符号用于标识页面状态的变化。当页面中的路由发生改变时,Vue.js会使用Hash模式来更新URL,并在页面中渲染相应的组件。

  • Hash模式是通过监听hashChange事件来实现的,前端js把当前hash地址对应的组件渲染到浏览器中。
  • 在地址栏URL上有#号。
  • 通常用于单页面应用(SPA),支持页面内的导航,不会刷新页面,也不会影响服务器。
  • Hash出现在URL中,但不包括在http请求中,对后端没有影响。
  • 在进行URL跳转时,如果只改变hash,不会重新加载页面。
hashchange 事件:

当hash值改变时会触发这个事件,通过 location.hash 获取到最新的 hash 值

注意:

  • hash 值的变化不会导致浏览器像服务器发送请求
  • location.hash可以获取hash值
  • hashchange是hash值发生改变的调用的函数

语法:

window.onhashchange = function () {
  console.log(location.hash);
};

// 或

window.addEventListener('hashchange', ()=>{
    console.log(location.hash);
});


三、history模式
http://example.com/home

History模式是另一种URL管理模式,它使用HTML5的History API来实现URL的变化和页面的刷新。在History模式下,URL中的#符号被移除,取而代之的是通过History API来管理页面的状态。


History模式的优点在于它能够实现平滑的页面过渡,提高用户体验。同时,由于URL中不包含#符号,因此也适用于搜索引擎优化。然而,History模式需要在服务器端进行额外的配置,以确保能够正确地处理不同的URL路径请求。

  • History模式是通过调用history.pushState方法(或者replaceState)并且监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新。
  • 需要服务器端做额外的配置,否则可能会出现刷新页面时的404错误。
  • 在进行URL跳转时,即使只改变hash,也需要重新加载页面(如果当前页面不是SPA)。
  • 支持浏览器的前进、后退功能。
方法:
1、history.go():

通过当前页面的相对位置从浏览器历史记录(会话记录)异步加载页面。

参数:

  • 参数为 -1 的时候为上一页,
  • 参数为 1 的时候为下一页。
  • 当你指定了一个越界值,例如:当会话历史记录中没有之前访问的页面时,则传参的值为 -1,那么这个方法没有任何效果也不会报错。
  • 调用没有参数的 go() 方法或者参数值为 0 时,重新载入当前页面。
  • Internet Explorer 允许你指定一个字符串,而不是整数,以转到历史记录列表中的特定 URL。
2、history.back():

此异步方法转到浏览器会话历史的上一页,与用户单击浏览器的 Back 按钮的行为相同。等价于 history.go(-1)。

调用此方法回到会话历史的第一页之前没有效果并且不会引发异常。


3、history.forward():

此异步方法转到浏览器会话历史的下一页,与用户单击浏览器的 Forward 按钮的行为相同。等价于 history.go(1)。


调用此方法超越浏览器历史记录中最新的页面没有效果并且不会引发异常。


4、History.replaceState()

替换当前页在历史记录中的信息

语法:

history.replaceState(stateObj, title[, url])

参数:


stateObj:状态对象是一个 JavaScript 对象,它与传递给 replaceState 方法的历史记录实体相关联。


title:大部分浏览器忽略这个参数, 将来可能有用。在此处传递空字符串应该可以防止将来对方法的更改。或者,你可以为该状态传递简短标题。


url:可选,历史记录实体的 URL. 新的 URL 跟当前的 URL 必须是同源; 否则 replaceState 抛出一个异常。

5、History.pushState()

向历史记录中追加一条记录

语法:

pushState(stateObj, title, url)

参数:

  • stateObj:一个用于表示历史记录状态的JavaScript对象。这个对象的内容会被添加到浏览器的历史堆栈中。这个参数是可选的。
  • title:为新的历史记录条目提供标题。这个参数通常可以设置为null,因为大多数浏览器在显示历史记录列表时并不使用这个标题。
  • url:可选,要添加到历史记录中的新URL。这个 URL 必须与当前页面处于同一个域中,否则浏览器可能会阻止这个操作。


优势:


  • pushState()设置的新的url可以是于当前url同源的任意url,而hash只可修改#后面的部分,因此只能设置与当亲url同文档的url。


  • pushState()设置的新的url可以与当前url一摸一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来的不一样才会触发动作将记录添加到栈中。
  • pushState()通过stateObject参数可以添加任意类型的数据到记录中;而hash只可添加短字符串。


当你在SPA中使用history.pushState()或者history.replaceState()时,你可能会希望更改浏览器的URL,但是不刷新页面。这可以让你的SPA具有更好的用户体验,因为用户可以点击浏览器的后退和前进按钮来导航,而不需要在你的应用中进行额外的点击。

popState 事件

每当同一个文档的浏览历史(即history)出现变化时,就会触发popState事件。


注意:


  • 仅仅调用pushState方法或replaceState方法,并不会触发该事件,只有用户点击浏览器后退和前进按钮时,或者使用js调用back、forward、go方法时才会触发。
  • 该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件不会被触发。
  • 页面第一次加载的时候,浏览器不会触发popState事件。

语法:

window.onpopstate = function (event) {
  console.log('location: ' + document.location);
  console.log('state: ' +JSON.stringify(event.state));
};

// 或

window.addEventListener('popstate', function(event) {
  console.log('location: ' + document.location);
  console.log('state: ' + JSON.stringify(event.state));
});


四、nginx配置

hash模式下,仅hash符号#之前的内容会被包含在请求中,比如http://www.example.com/home 因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回404错误;

history模式下,前端的url必须和实际后端发起请求的url一致,如http://example.com/about/id 。如果后端缺少对/about/id 的路由处理,将返回404错误。


在Vue.js中,可以使用vue-router库来实现Hash模式和History模式。通过配置vue-router的mode属性,可以选择使用Hash模式或History模式。需要注意的是,项目部署生产后,hash 模式能够正常使用,而 history 模式访问不到资源。hash 的改变不会发生请求,因此不影响服务器端,所以 nginx 不会拦截,而 history 模式则需要设置可访问的配置。


比如http://www.example.com/home 如果不进行配置,那么 nginx 默认会去找服务器目录下的 home 文件,而我们想要的效果则是依旧寻找 index 文件,home 则交给前端去处理,nginx 使用 try_files 配置即可实现该效果。

location / { 
 root /www/wwwroot; 
 index index.html; 
 try_files $uri $uri/ /index.html; 
}
五、原生 Node.js配置
const http = require('http')
const fs = require('fs')
const httpPort = 80

http.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)
})


六、注意

给个警告,因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后再给出一个 404 页面。

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

或者,如果你使用 Node.js 服务器,你可以用服务端路由匹配到来的 URL,并在没有匹配到路由的时候返回 404,以实现回退。

更多详情请查阅 Vue 服务端渲染文档


七、如何选择合适的路由模式

使用 Hash 模式:

  • 如果你的项目不需要考虑兼容性问题,或者需要在旧版浏览器中支持路由功能。
  • 如果你希望简化部署过程,只需将静态文件部署到服务器即可。

使用 History 模式:

  • 如果你希望 URL 更加美观、简洁,不希望在 URL 中出现 # 符号。
  • 如果你可以进行服务器配置,确保在直接访问 URL 时返回正确的页面。
  • 如果你的项目不需要考虑旧版浏览器的兼容性问题。
目录
相关文章
|
22天前
|
监控 前端开发 JavaScript
前端工程化和传统前端开发的区别是什么?
前端工程化相比传统前端开发,在开发模式、代码组织与管理、构建与部署流程、团队协作、性能优化以及技术选型等方面都有了显著的改进和提升,能够更好地应对现代前端应用开发的复杂性和高要求。
|
1月前
|
前端开发 JavaScript 开发者
React与Vue:前端框架的巅峰对决与选择策略
【10月更文挑战第23天】React与Vue:前端框架的巅峰对决与选择策略
|
1月前
|
前端开发 JavaScript 数据管理
React与Vue:两大前端框架的较量与选择策略
【10月更文挑战第23天】React与Vue:两大前端框架的较量与选择策略
|
1月前
|
前端开发 JavaScript 开发者
React与Vue:前端框架的巅峰对决与选择策略
【10月更文挑战第23天】 React与Vue:前端框架的巅峰对决与选择策略
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
155 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
45 0
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
109 1
|
2月前
|
前端开发 算法 测试技术
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
本文对比测试了通义千文、文心一言、智谱和讯飞等多个国产大模型在处理基础计数问题上的表现,特别是通过链式推理(COT)提示的效果。结果显示,GPTo1-mini、文心一言3.5和讯飞4.0Ultra在首轮测试中表现优秀,而其他模型在COT提示后也能显著提升正确率,唯有讯飞4.0-Lite表现不佳。测试强调了COT在提升模型逻辑推理能力中的重要性,并指出免费版本中智谱GLM较为可靠。
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT