开篇日常立个flag……

前言

最近在做一些应用,类似于单页应用,想实现类似于 Vue 路由的效果。

但是个人 Vue 基础四舍五入约等于无,而且看着 Vue-router 吃力+用不起来(因为我的项目前后端不分离,而且使用的 js 语法基本上停留在远古时代:ES5甚至更久远以前……)

之前尝试过模拟,但是模拟太痛苦了,而且一堆问题,还不好维护。

于是想着自己用原生 js 写一个简单的单页应用路由吧。

效果

话不多说,先上效果图

源码

gitee:https://gitee.com/chen3322275/singlepagerouter/

思路与设定

-思路

1、location.hash 可以修改页面的锚点

2、当前页面锚点的改变,会触发 hashchange 事件

这样,注册一个 hashchange 事件,监听 hash 的变化,切换页面指定元素的显示与隐藏,可以达到单页应用的效果。

-一些设定

首先我们约定一个路由对象 route,route 包含两个属性,即 id 和 handle。

接着,我们将会设定一个路由表,记录为 routes,为一个 route 对象的数组。

最后,实现一个路由器 Router 对象,还监听以及操作路由跳转。

三者的定义如下:

  1. //route 单个路由对象
  2. var route = { id: 'next', handle: function () { console.log("切换到next");}
  3.  
  4. //routes 路由表
  5. var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切换到next");} }]
  6.  
  7. //router 路由器
  8. var router = new Router(routes);

注释:

route 对象的 id,除了为操作元素(一般为 div)的 id 外,还将会是 hash 的值。

handle 为一个函数,类似于回调函数,在切换该路由时执行。

若 id 为空,则隐藏路由表所有路由。

Router 模块 js代码

直接上代码

  1. /*
  2. * 模块:单页应用路由
  3. * 作者:cls
  4. * 日期:2021.04.17
  5. * 使用:var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切换到next");} }]
  6. * var router = new Router(routes);
  7. */
  8. function Router(routes, defaultRoute) {
  9. var othis = this;
  10.  
  11. //路由初始化
  12. routes && this.init(routes, defaultRoute);
  13.  
  14. //绑定 hashchange 事件
  15. window.addEventListener("hashchange", function() {
  16. let route = location.hash.slice(1) || "";
  17. this.oldRoute == this.currentRoute;
  18. this.currentRoute = route;
  19. othis.changePage(route);
  20. });
  21. }
  22.  
  23. //初始化,可多次初始化
  24. Router.prototype.init = function(routes, defaultRoute) {
  25. if (routes == undefined || routes.length == undefined || routes.length == 0) {
  26. console.error("Router初始化失败:routes错误!");
  27. return;
  28. }
  29. this.routes = routes;
  30. this.currentRoute = location.hash.slice(1) || defaultRoute || routes[0].id; //当前路由获取顺序
  31. this.oldRoute = "";
  32. location.hash || history.replaceState(null, null, '#' + this.currentRoute); //hash为空,切换当前hash
  33. this.changePage(this.currentRoute);
  34. this.oldRoute = location.hash;
  35. }
  36.  
  37. //切换路由
  38. Router.prototype.push = function(route, callback) {
  39. //获取route
  40. switch (typeof(route)) {
  41. case "string":
  42.  
  43. break;
  44. case "undefined":
  45. route = location.hash.slice(1) || "";
  46. break;
  47. case "number":
  48. route = this.routes[route] || "";
  49. break;
  50. case "object":
  51. route = route.id || "";
  52. break;
  53. }
  54. location.hash = route; //切换hash,接下来的事情交给hashchange去做。如果与上一次的route一致,不会触发hashchange事件
  55. }
  56.  
  57. //切换页面:route为字符串,为空则隐藏所有路由
  58. Router.prototype.changePage = function(route) {
  59. for (let i = 0; i < this.routes.length; i++) {
  60. let e = document.getElementById(routes[i].id);
  61. if (routes[i].id == route) {
  62. e && (e.style.display = "block");
  63. (typeof(routes[i].handle) === "function") && routes[i].handle(); //handle 存在,执行函数
  64. } else {
  65. e && (e.style.display = "none");
  66. }
  67. }
  68. }

  

测试页面的 Html 代码

  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>单页路由测试</title>
  7. </head>
  8. <body>
  9. <div>
  10. <h1>Welcome</h1>
  11.  
  12. <a href="#">空的</a>
  13. <a href="#index">index啊啊啊</a>
  14. <button onclick="router.push('next')">next测试</button>
  15.  
  16. <div id="index">
  17. index啊啊啊
  18. </div>
  19. <div id="next">
  20. next啊啊啊 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
  21. </div>
  22. </div>
  23.  
  24. <script src="~/js/site.js"></script>
  25. <script>
  26. //路由表
  27. var routes = [
  28. { id: '' },
  29. { id: 'index' },
  30. { id: 'next', handle: function () { console.log("切换到next"); console.log(this); } }
  31. ]
  32.  
  33. //路由器
  34. var router = new Router(routes, 'index');
  35. </script>
  36. </body>
  37. </html>

  

使用说明

1、整个应用生命周期,只创建一次路由器,即 var router = new Router() 时,只 new 一次。(否则会注册多次 hashchange 事件)

2、路由器创建以后,可以使用 router.init() 切换路由表

3、控制 router 跳转路由使用 router.push(route) 方法,输入的 route 可以是路由表的下标,也可以是路由表 id 的字符串,也可以是 route 对象,若没有输入,则默认不会跳转。

参考来源

鱼丸粗面不要香菜 的 使用js实现单页应用路由转跳功能

小蚊 的 用原生js做单页应用(博文挂掉了,链接复制不到)

前端 JS 原生 javascript 和 location.hash 实现一个单页应用的路由 router的更多相关文章

  1. js 利用iframe和location.hash跨域解决的方法,java图片上传回调JS函数跨域

    奶奶的:折腾了我二天,最终攻克了!网上有非常多样例. 但跟我的都不太一样,费话不多说了,上图   上代码: IE ,firefix,chrome 測试通过 js :这个主页面,部分代码, functi ...

  2. 前端js之JavaScript

    知识预览 一小知识 二 JavaScript的基础 BOM对象 DOM对象 实例练习 js拓展 小知识 核心(ECMAScript) 文档对象模型(DOM) Document object model ...

  3. JS原生javascript可以直接写id名来选取元素

    平时一直用document.getElementById();方法通过id名来获取元素. 最近发现可以直接写id名来获取元素: <body> <div id="kk&quo ...

  4. 纯JS写的一款记录事项的单页应用

    要点: 1.使用localStorage存储 2._change_record_progress函数以字符串作为参数,用eval执行这个参数 3.使用了jQuery自定义事件,便于数据改变时实时更新显 ...

  5. 前端html、Javascript、CSS技术小结

    简单地总结了一下前端用过的html.javascript.css技术,算是清点一下,做个大略的小结,为进一步的学习给个纲领. 一.HTML 由于HTML5的兴起,简单地判断一个网页是否是html5网页 ...

  6. arguments.callee 调用函数自身用法----JSON.parse()和JSON.stringify()前端js数据转换json格式

    arguments.callee 调用函数自身用法 arguments.callee 在哪一个函数中运行,它就代表哪个函数. 一般用在匿名函数中. 在匿名函数中有时会需要自己调用自己,但是由于是匿名函 ...

  7. 前端MVC Vue2学习总结(五)——表单输入绑定、组件

    一.表单输入绑定 1.1.基础用法 你可以用 v-model 指令在表单控件元素上创建双向数据绑定.它会根据控件类型自动选取正确的方法来更新元素.尽管有些神奇,但 v-model 本质上不过是语法糖, ...

  8. 《移动Web前端高效开发实战》笔记4--打造单页应用SPA

    路由是一个单页应用的核心,大部分前端框架都实现了一个复杂的路由库,包括动态路由,路由钩子,组件生命周期甚至服务器端渲染等复杂的功能.但是对于前端开发者而言,路由组件的核心是URL路径到函数的映射,了解 ...

  9. Javascript 与 SPA单页Web富应用

    书单推荐 # <单页Web应用:JavaScript从前端到后端> http://download.csdn.net/detail/epubitbook/8720475 # <MVC ...

随机推荐

  1. Unity 定点投射固定高度抛物线

    假设同一平面中有AB两点,A点向B点水平射击,很容易想象子弹会沿由A指向B的向量方向前进,经过时间t后到达B点,若此时A点不再水平射击,改为以抛物线的方式向B点投射,同样需要在时间t后击中B点,那么如 ...

  2. SpringBoot常见的异常问题

    1. org.mybatis.logging.LoggerFactory Springboot启动报错 Caused by: java.lang.ClassNotFoundException: org ...

  3. Vue项目的创建、路由、及生命周期钩子

    目录 一.Vue项目搭建 1.环境搭建 2.项目的创建 3.pycharm配置并启动vue项目 4.vue项目目录结构分析 5.Vue根据配置重新构建依赖 二.Vue项目创建时发生了什么 三.项目初始 ...

  4. while(1)和system("pause")区别

    我们在调试时,有时候会用到这两个语句. 1.显而易见,第一个是一个循环函数,占cpu.占内存: 2.system("pause")是一个系统调用,占内存,不占cpu;这个开销还是有 ...

  5. Kubernetes 实战 —— 01. Kubernetes 介绍

    简介 P2 Kubernetes 能自动调度.配置.监管和故障处理,使开发者可以自主部署应用,并且控制部署的频率,完全脱离运维团队的帮助. Kubernetes 同时能让运维团队监控整个系统,并且在硬 ...

  6. [Java Tutorial学习分享]接口与继承

    目录 接口 概述 Java 中的接口 使用接口作为API 定义一个接口 The Interface Body 实现接口 使用接口作为类型 进化的接口 默认方法 扩展包含默认方法的接口 静态方法 接口总 ...

  7. 剑指 Offer 09. 用两个栈实现队列 +java中栈和队列的使用

    剑指 Offer 09. 用两个栈实现队列 题目链接 class CQueue { private Stack<Integer> sta1; private Stack<Intege ...

  8. 如何使用 HttpReports 监控 .NET Core 应用程序

    简介 HttpReports 基于.NET Core 开发的APM监控系统,使用MIT开源协议,主要功能包括,统计, 分析, 可视化, 监控,追踪等,适合在中小项目中使用. github:https: ...

  9. Linux下制作Windows启动U盘的工具

    Linux下制作Windows启动U盘的工具 很多人说Linux下制作Windwos启动盘要用GRUB4DOS建立引导,其实不用,有专门的工具的,就像Windows下有Rufus制作Linux启动U盘 ...

  10. SpringCloud-服务与注册

    SpringCloud- Eureka服务注册与发现 1.概述 springcloud是一个非常优秀的微服务框架,要管理众多的服务,就需要对这些服务进行治理,管理每个服务与每个服务之间的依赖关系,可以 ...