前端 JS 原生 javascript 和 location.hash 实现一个单页应用的路由 router
开篇日常立个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 对象,还监听以及操作路由跳转。
三者的定义如下:
//route 单个路由对象
var route = { id: 'next', handle: function () { console.log("切换到next");} //routes 路由表
var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切换到next");} }] //router 路由器
var router = new Router(routes);
注释:
route 对象的 id,除了为操作元素(一般为 div)的 id 外,还将会是 hash 的值。
handle 为一个函数,类似于回调函数,在切换该路由时执行。
若 id 为空,则隐藏路由表所有路由。
Router 模块 js代码
直接上代码
/*
* 模块:单页应用路由
* 作者:cls
* 日期:2021.04.17
* 使用:var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切换到next");} }]
* var router = new Router(routes);
*/
function Router(routes, defaultRoute) {
var othis = this; //路由初始化
routes && this.init(routes, defaultRoute); //绑定 hashchange 事件
window.addEventListener("hashchange", function() {
let route = location.hash.slice(1) || "";
this.oldRoute == this.currentRoute;
this.currentRoute = route;
othis.changePage(route);
});
} //初始化,可多次初始化
Router.prototype.init = function(routes, defaultRoute) {
if (routes == undefined || routes.length == undefined || routes.length == 0) {
console.error("Router初始化失败:routes错误!");
return;
}
this.routes = routes;
this.currentRoute = location.hash.slice(1) || defaultRoute || routes[0].id; //当前路由获取顺序
this.oldRoute = "";
location.hash || history.replaceState(null, null, '#' + this.currentRoute); //hash为空,切换当前hash
this.changePage(this.currentRoute);
this.oldRoute = location.hash;
} //切换路由
Router.prototype.push = function(route, callback) {
//获取route
switch (typeof(route)) {
case "string": break;
case "undefined":
route = location.hash.slice(1) || "";
break;
case "number":
route = this.routes[route] || "";
break;
case "object":
route = route.id || "";
break;
}
location.hash = route; //切换hash,接下来的事情交给hashchange去做。如果与上一次的route一致,不会触发hashchange事件
} //切换页面:route为字符串,为空则隐藏所有路由
Router.prototype.changePage = function(route) {
for (let i = 0; i < this.routes.length; i++) {
let e = document.getElementById(routes[i].id);
if (routes[i].id == route) {
e && (e.style.display = "block");
(typeof(routes[i].handle) === "function") && routes[i].handle(); //handle 存在,执行函数
} else {
e && (e.style.display = "none");
}
}
}
测试页面的 Html 代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>单页路由测试</title>
</head>
<body>
<div>
<h1>Welcome</h1> <a href="#">空的</a>
<a href="#index">index啊啊啊</a>
<button onclick="router.push('next')">next测试</button> <div id="index">
index啊啊啊
</div>
<div id="next">
next啊啊啊 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
</div>
</div> <script src="~/js/site.js"></script>
<script>
//路由表
var routes = [
{ id: '' },
{ id: 'index' },
{ id: 'next', handle: function () { console.log("切换到next"); console.log(this); } }
] //路由器
var router = new Router(routes, 'index');
</script>
</body>
</html>
使用说明
1、整个应用生命周期,只创建一次路由器,即 var router = new Router() 时,只 new 一次。(否则会注册多次 hashchange 事件)
2、路由器创建以后,可以使用 router.init() 切换路由表
3、控制 router 跳转路由使用 router.push(route) 方法,输入的 route 可以是路由表的下标,也可以是路由表 id 的字符串,也可以是 route 对象,若没有输入,则默认不会跳转。
参考来源
小蚊 的 用原生js做单页应用(博文挂掉了,链接复制不到)
前端 JS 原生 javascript 和 location.hash 实现一个单页应用的路由 router的更多相关文章
- js 利用iframe和location.hash跨域解决的方法,java图片上传回调JS函数跨域
奶奶的:折腾了我二天,最终攻克了!网上有非常多样例. 但跟我的都不太一样,费话不多说了,上图 上代码: IE ,firefix,chrome 測试通过 js :这个主页面,部分代码, functi ...
- 前端js之JavaScript
知识预览 一小知识 二 JavaScript的基础 BOM对象 DOM对象 实例练习 js拓展 小知识 核心(ECMAScript) 文档对象模型(DOM) Document object model ...
- JS原生javascript可以直接写id名来选取元素
平时一直用document.getElementById();方法通过id名来获取元素. 最近发现可以直接写id名来获取元素: <body> <div id="kk&quo ...
- 纯JS写的一款记录事项的单页应用
要点: 1.使用localStorage存储 2._change_record_progress函数以字符串作为参数,用eval执行这个参数 3.使用了jQuery自定义事件,便于数据改变时实时更新显 ...
- 前端html、Javascript、CSS技术小结
简单地总结了一下前端用过的html.javascript.css技术,算是清点一下,做个大略的小结,为进一步的学习给个纲领. 一.HTML 由于HTML5的兴起,简单地判断一个网页是否是html5网页 ...
- arguments.callee 调用函数自身用法----JSON.parse()和JSON.stringify()前端js数据转换json格式
arguments.callee 调用函数自身用法 arguments.callee 在哪一个函数中运行,它就代表哪个函数. 一般用在匿名函数中. 在匿名函数中有时会需要自己调用自己,但是由于是匿名函 ...
- 前端MVC Vue2学习总结(五)——表单输入绑定、组件
一.表单输入绑定 1.1.基础用法 你可以用 v-model 指令在表单控件元素上创建双向数据绑定.它会根据控件类型自动选取正确的方法来更新元素.尽管有些神奇,但 v-model 本质上不过是语法糖, ...
- 《移动Web前端高效开发实战》笔记4--打造单页应用SPA
路由是一个单页应用的核心,大部分前端框架都实现了一个复杂的路由库,包括动态路由,路由钩子,组件生命周期甚至服务器端渲染等复杂的功能.但是对于前端开发者而言,路由组件的核心是URL路径到函数的映射,了解 ...
- Javascript 与 SPA单页Web富应用
书单推荐 # <单页Web应用:JavaScript从前端到后端> http://download.csdn.net/detail/epubitbook/8720475 # <MVC ...
随机推荐
- springCloud中的注册中心Nacos
springCloud中的注册中心Nacos 三个模块: 1.注册中心 2.服务提供者(生产者) 提供服务 3.服务消费者(消费者)调用服务 流程:消费者和生产者都要向注册中心注册,注册的是二者中服务 ...
- 物联网网关开发:基于MQTT消息总线的设计过程(上)
道哥的第 021 篇原创 目录 一.前言 二.网关的作用 2.1 指令转发 2.2 外网通信 2.3 协议转换 2.4 设备管理 2.5 边沿计算(自动化控制) 三.网关内部进程之间的通信 3.1 网 ...
- Vue学习笔记-Django REST framework3后端接口API学习
一 使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7 (Windows x86- ...
- vue之provide和inject跨组件传递属性值失败(父组件向子组件传值的两种方式)
简单介绍:当一个子组件需要用到父组件的父组件的某些参数.那么这个时候为了避免组件重复传参,使用vue的依赖注入是个不错的方法,直接在最外层组件设置一个provide,内部不管多少嵌套都可以直接取到最外 ...
- Linux的启动过程及init进程
Linux下有三个特殊进程: idle进程(pid=0)idle进程其前身是系统创建的第一个进程,0号进程,也唯一一个没有通过fork()或者kernel_thread产生的进程,由系统自动创建,运行 ...
- 迭代器 (Iterator) 和 生成器 (Generator)
其他章节请看: es6 快速入门 系列 迭代器 (Iterator) 和 生成器 (Generator) 试图解决的问题 let colors = ['red', 'blue', 'green', ' ...
- Flask:Jinjia模板
Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能. 一.变量 1.1 手动传入的变量: 基本类型:{{ var }} 字 ...
- PVE更新WEB管理地址
PVE也是一台Linux系统,如果PVE更换了网络环境,比如从家里拿到了办公室,那么就需要对其更新网络,才能让其它机器访问到它的8006管理地址. 具体做法是通过修改配置文件来更改IP. 更新网卡配置 ...
- 剑指 Offer 56 - I. 数组中数字出现的次数 + 分组异或
剑指 Offer 56 - I. 数组中数字出现的次数 Offer_56_1 题目描述 解题思路 java代码 /** * 方法一:数位方法 */ class Offer_56_1_2 { publi ...
- C++ 中的虚函数表及虚函数执行原理
为了实现虚函数,C++ 使用了虚函数表来达到延迟绑定的目的.虚函数表在动态/延迟绑定行为中用于查询调用的函数. 尽管要描述清楚虚函数表的机制会多费点口舌,但其实其本身还是比较简单的. 首先,每个包含虚 ...