在chrome(版本 70.0.3538.110)测试正常

编写涉及:css, html,js, node(koa)

在线演示codepen

html代码

  1. <div class="hash">
  2. <div class="title">hash 路由</div>
  3. <a href="#/one">hash 1</a> <a href="#/two">hash 2</a> <a href="#/three">hash 3</a> <a onclick="hashRoute.skip('other')">other</a>
  4. <div id="hashContent"></div>
  5. </div>
  6. <div class="history">
  7. <div class="title">history 路由</div>
  8. <div>
  9. <button onclick="historyRoute.skip('pushStateOne')">history.pushState(1)</button>
  10. <button onclick="historyRoute.skip('pushStateTwo')">history.pushState(2)</button>
  11. <button onclick="historyRoute.skip('pushStateThree')">history.pushState(3)</button>
  12. <button onclick="historyRoute.skip('pushStateTwo')">history.replaceState(pushStateTwo)</button>
  13. <button onclick="historyRoute.skip('go')">history.go(2)</button>
  14. <button onclick="historyRoute.skip('forward')">history.forward()</button>
  15. <button onclick="historyRoute.skip('back')">history.back()</button>
  16. </div>
  17. <div id="historyContent"></div>
  18. </div>

css代码

  1. .hash a {
  2. display: inline-block;
  3. padding: 5px 8px;
  4. margin: 10px 10px 10px 0;
  5. font-size: 15px;
  6. text-decoration: none;
  7. border: 0;
  8. cursor: pointer;
  9. color: #fff;
  10. background-color: rgb(17, 130, 236);
  11. }
  12. .title{
  13. margin: 10px 0;
  14. padding: 5px 8px;
  15. border-left: rgb(168, 168, 168) solid 2px;
  16. background-color: rgb(230, 230, 230);
  17. }
  18. .hash div:last-child{
  19. padding: 6px;
  20. min-height: 100px;
  21. background-color: rgb(243, 243, 243);
  22. }
  23. .history{
  24. margin: 10px 0;
  25. }
  26. .history button {
  27. padding: 8px 10px;
  28. border: 0;
  29. color: #fff;
  30. background-color: rgb(250, 144, 44);
  31. }
  32. .history div:last-child{
  33. margin-top: 10px;
  34. padding: 6px;
  35. min-height: 100px;
  36. background-color: rgb(243, 243, 243);
  37. }

JavaScript代码

hash方式

  1. class HashRoute {
  2. setRoute() {
  3. const commandObj = {
  4. one: 'page one',
  5. two: 'page two',
  6. three: 'page three'
  7. }
  8. const hashRoute = location.hash ? location.hash.slice(2) : 'one'
  9. let re = commandObj[hashRoute]
  10. document.getElementById('hashContent').innerHTML = re ? re : 'page not find'
  11. }
  12. skip(path) {
  13. window.location.hash= `#/${path}`
  14. }
  15. init() {
  16. window.addEventListener('DOMContentLoaded', this.setRoute)
  17. // 1.直接更改浏览器地址,在最后面增加或改变#hash;
  18. // 2.通过改变location.href 或 location.hash的值;
  19. // 3.通过触发点击带锚点的链接;
  20. // 4.浏览器前进后退可能导致hash的变化,前提是两个网页地址中的hash值不同
  21. window.addEventListener('hashchange', this.setRoute)
  22. }
  23. }
  24. const hashRoute = new HashRoute()
  25. hashRoute.init()

history 方式

浏览器端代码

  1. // 服务端有效
  2. class HistoryRoute {
  3. constructor() {
  4. this.currentPath = ''
  5. }
  6. renderView(component) {
  7. const route = {
  8. pushStateOne: 'route pushState one',
  9. pushStateTwo: 'route pushState two',
  10. pushStateThree: 'route pushState three',
  11. replaceState: 'route replaceState',
  12. go: 'route go',
  13. forward: 'route forward',
  14. back: 'route back',
  15. notFind: 'not find',
  16. }
  17. document.getElementById('historyContent').innerHTML = route[component]
  18. }
  19. // 这里所有涉及的跳转都用js方式,不采用a标签(采用a标签请设置拦截)
  20. skip(path) {
  21. const commandObj = {
  22. pushStateOne: () => {
  23. history.pushState({ path }, path,path)
  24. this.renderView(path)
  25. },
  26. pushStateTwo: () => {
  27. history.pushState({ path }, path, path)
  28. this.renderView(path)
  29. },
  30. pushStateThree: () => {
  31. history.pushState({ path }, path, path)
  32. this.renderView(path)
  33. },
  34. replaceState: () => {
  35. // 是用来修改当前的history实体而不是创建一个新的,比如连转顺序为1,2,3,1执行replaceState(2),再执行back(),返回1,而不是3
  36. history.replaceState({ path }, path, path)
  37. this.renderView(path)
  38. },
  39. go: () => {
  40. history.go(2)
  41. this.renderView('go')
  42. },
  43. forward: () => {
  44. history.forward()
  45. this.renderView('forward')
  46. },
  47. back: () => {
  48. history.back()
  49. },
  50. }
  51. this.currentPath = path;
  52. commandObj[path]()
  53. }
  54. init() {
  55. window.addEventListener('DOMContentLoaded', () => {
  56. // 针对F5刷新问题:
  57. // 1.可以使用?后面跟参数形式
  58. // 2.统一入口利用忽略地址方式(后端配置 /page/:path 忽略page后跟的所有地址,通过前端去请求page后的对应路由数据,如下)
  59. const path = location.href.split('/page/')
  60. this.skip(path[1])
  61. })
  62. // 调用history.pushState()或history.replaceState()不会触发popstate。
  63. // 只有在用户点击前进回退按钮,(或history.back(),forward,go)
  64. window.addEventListener('popstate', (event) => {
  65. console.log('popstate', this.currentPath, event.state);
  66. const { state } = event
  67. if (state && state.path) {
  68. this.renderView(state.path)
  69. } else {
  70. this.renderView('404')
  71. }
  72. })
  73. }
  74. }
  75. const historyRoute = new HistoryRoute()
  76. historyRoute.init();

服务器端

  1. // 结合前端,可以用以下方式处理
  2. router.get('/page/:path', (ctx, next) => {
  3. ctx.response.type = 'html';
  4. // 此处的singlePageRoute.html为单页面html容器,即放置本文中的所有代码文件
  5. ctx.response.body = fs.createReadStream('./dist/public/files/singlePageRoute.html');
  6. return next();
  7. })

若有疑问或错误,请留言,谢谢!Github blog issues

利用hash或history实现单页面路由的更多相关文章

  1. 详解单页面路由的几种实现原理(附demo)

    前言 路由是每个单页面网站必须要有的,所以,理解一下原理,我觉得还是比较重要的. 本篇,基本不会贴代码,只讲原理,代码在页底会有githup地址,主意,一定要放在服务本地服务器里跑(因为有ajax), ...

  2. 移动H5页面微信支付踩坑之旅(微信支付、单页面路由模拟、按钮加锁、轮询等常见功能)

    开发背景: .net混合开发的vue模板语法的单页面应用,所以不存在脚手架以及没有路由可以跳转. 项目描述: 需要写两个页面,在订单详情页需要点击“请输入手机号”进入手机号绑定页面,手机号绑定成功后自 ...

  3. AngularJS单页面路由配置恩,理解了就很简单啦

    利用route实现单页面跳转功能 利用angularJS开发流程 1)配置好angularJS开发环境 2)利用 yo angular projectname创建项目目录 3)删除掉系统自动生成的一些 ...

  4. 简单单页面路由跳转demo

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. webpack解决单页面路由问题

    index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  6. angular ,require.js, angular-async-loader实现单页面路由,控制器js文件分离

    https://github.com/heboliufengjie/appRoute/tree/re re 分支,实现,路由配置,控制器js文件分离

  7. hash和history路由的区别

    在了解路由模式前,我们先看下 什么是单页面应用,vue-router  的实现原理是怎样的,这样更容易理解路由. SPA与前端路由 SPA(单页面应用,全程为:Single-page Web appl ...

  8. 浅谈HTML5单页面架构(二)——backbone + requirejs + zepto + underscore

    本文转载自:http://www.cnblogs.com/kenkofox/p/4648472.html 上一篇<浅谈HTML5单页面架构(一)--requirejs + angular + a ...

  9. H5单页面架构:backbone + requirejs + zepto + underscore

    首先,来看看整个项目结构. 跟上一篇angular类似,libs里多了underscore和zepto.三个根目录文件: index.html:唯一的html main.js:requirejs的配置 ...

随机推荐

  1. HDU 1561:The more, The Better(有依赖的树型背包)

    http://acm.hdu.edu.cn/showproblem.php?pid=1561 题意:有n个点,容量为m,每个点有一个价值,还给出n条边,代表选第i个点之前必须先选ai,问最多的价值能取 ...

  2. UVa 10480:Sabotage (最小割集)

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. 大规模SDN云计算数据中心组网的架构设计

    本文首先分析了在大规模SDN数据中心组网中遇到的问题.一方面Underlay底层组网规模受限于设备实际的转发能力和端口密度,单一Spine-leaf的Fabric架构无法满足大规模组网的需求:另一方面 ...

  4. 淺談Coach思考模式

    我現在是個窮屌,沒錯.我清楚的知道這一點,但是我也知道,我能改變. 之前幹了7年的評估行業,中間換了3家公司,第一家公司待的時間最長,待了5年.2018年開始,我就在思考轉行.之前在第一家企業接觸過一 ...

  5. 基于SpringBoot的WEB API项目的安全设计

    SpringBoot的开箱即用功能,大大降低了上手一个WEB应用的门槛,友好的REST接口支持,在SpringCloud微服务体系中可编程性大大提高,本篇基于一个面向企业调用方用户的WEB API项目 ...

  6. 20131221-Dom练习-第二十六天(未完)

    [1] //总结,写代码,一要动脑,理解用脑 //二要练,要动手,要有用身体记忆代码的觉悟,记忆用手 //三学编程最快的方法是,直接接触代码,用脑,用手接触代码 //面向对象的编码方式,对象还是对象, ...

  7. 开源框架Autofac使用入门

    目录导航 1.Autofac是什么 1.1什么是DI和IOC 1.2DI和IOC在项目中起到什么作用 2.Autofac如何使用 2.1下载 2.2代码Demo 2.3Demo分析 3总结 1.Aut ...

  8. 个人永久性免费-Excel催化剂功能第71波-定义名称管理器维护增强

    Excel使用得好坏一个分水岭之一乃是对定义名称的使用程度如何,大量合理地使用定义名称功能,对整个Excel的高级应用带来极大的便利性和日常公式函数嵌套的可读性得到很大的提升.Excel催化剂再次以插 ...

  9. Flink实战(八) - Streaming Connectors 编程

    1 概览 1.1 预定义的源和接收器 Flink内置了一些基本数据源和接收器,并且始终可用.该预定义的数据源包括文件,目录和插socket,并从集合和迭代器摄取数据.该预定义的数据接收器支持写入文件和 ...

  10. Android Studio电脑不支持HAXM的解决办法

    Intel HAXM is required to run this AVD. Your CPU does not support required features (VT-x or SVM). U ...