自己动手写一个前端路由插件

在单页应用上,前端路由并不陌生。单页应用是指在浏览器中运行的应用,在使用期间页面不会重新加载。 
      基本原理:以 hash 形式(也可以使用 History API 来处理)为例,当 url 的 hash 发生改变时,触发 hashchange 注册的回调,回调中去进行不同的操作,进行不同的内容的展示。 
      基于hash的前端路由优点是:能兼容低版本的浏览器。 
history 是 HTML5 才有的新 API,可以用来操作浏览器的 session history (会话历史)。 
      从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。

SPA的核心即是前端路由。何为路由呢?说的通俗点就是网址,比如https://www.talkingcoder.com/article/6333760306895988699;专业点就是每次GET或者POST等请求,在服务端有一个专门的正则配置列表,然后匹配到具体的一条路径后,分发到不同的Controller,然后进行各种操作后,最终将html或数据返回给前端,这就完成了一次IO。当然,目前绝大多数的网站都是这种后端路由,也就是多页面的,这样的好处有很多,比如页面可以在服务端渲染好直接返回给浏览器,不用等待前端加载任何js和css就可以直接显示网页内容,再比如对SEO的友好等。那SPA的缺点也是很明显的,就是模板是由后端来维护或改写。前端开发者需要安装整套的后端服务,必要还得学习像PHP或Java这些非前端语言来改写html结构,所以html和数据、逻辑混为一谈,维护起来即臃肿也麻烦。然后就有了前后端分离的开发模式,后端只提供API来返回数据,前端通过Ajax获取到数据后,再用一定的方式渲染到页面里,这么做的优点就是前后端做的事情分的很清楚,后端专注在数据上,前端专注在交互和可视化上,从此前后搭配,干活不累,如果今后再开发移动App,那就正好能使用一套API了,当然缺点也很明显,就是首屏渲染需要时间来加载css和js。这种开发模式被很多公司认同,也出现了很多前端技术栈,比如以jQuery+artTemplate+Seajs(requirejs)+gulp为主的开发模式所谓是万金油了。在Node.js出现后,这种现象有了改善,就是所谓的大前端,得益于Node.js和JavaScript的语言特性,html模板可以完全由前端来控制,同步或异步渲染完全由前端自由决定,并且由前端维护一套模板,这就是为什么在服务端使用artTemplate、React以及即将推出的Vue2.0原因了。那说了这么多,到底怎样算是SPA呢,其实就是在前后端分离的基础上,加一层前端路由。

前端路由,即由前端来维护一个路由规则。实现有两种,一种是利用url的hash,就是常说的锚点(#),JS通过hashChange事件来监听url的改变,IE7及以下需要用轮询;另一种就是HTML5的History模式,它使url看起来像普通网站那样,以"/"分割,没有#,但页面并没有跳转,不过使用这种模式需要服务端支持,服务端在接收到所有的请求后,都指向同一个html文件,不然会出现404。所以,SPA只有一个html,整个网站所有的内容都在这一个html里,通过js来处理。

前端路由的优点有很多,比如页面持久性,像大部分音乐网站,你都可以在播放歌曲的同时,跳转到别的页面而音乐没有中断,再比如前后端彻底分离。前端路由的框架,通用的有Director,更多还是结合具体框架来用,比如Angular的ngRouter,React的ReactRouter,以及我们后面用到的Vue的vue-router。这也带来了新的开发模式:MVC和MVVM。如今前端也可以MVC了,这也是为什么那么多搞Java的钟爱于Angular。

开发一个前端路由,主要考虑到页面的可插拔、页面的生命周期、内存管理等。

(function() {
	window.Router = function() {
		var self = this;

		self.hashList = {}; /* 路由表 */
		self.index = null;
		self.key = ‘!‘;

		window.onhashchange = function() {
			self.reload();
		};
	};

	/**
	 * 添加路由,如果路由已经存在则会覆盖
	 * @param addr: 地址
	 * @param callback: 回调函数,调用回调函数的时候同时也会传入相应参数
	 */
	Router.prototype.add = function(addr, callback) {
		var self = this;

		self.hashList[addr] = callback;
	};

	/**
	 * 删除路由
	 * @param addr: 地址
	 */
	Router.prototype.remove = function(addr) {
		var self = this;

		delete self.hashList[addr];
	};

	/**
	 * 设置主页地址
	 * @param index: 主页地址
	 */
	Router.prototype.setIndex = function(index) {
		var self = this;

		self.index = index;
	};

	/**
	 * 跳转到指定地址
	 * @param addr: 地址值
	 */
	Router.prototype.go = function(addr) {
		var self = this;

		window.location.hash = ‘#‘ + self.key + addr;
	};

	/**
	 * 重载页面
	 */
	Router.prototype.reload = function() {
		var self = this;

		var hash = window.location.hash.replace(‘#‘ + self.key, ‘‘);
		var addr = hash.split(‘/‘)[0];
		var cb = getCb(addr, self.hashList);
		if(cb != false) {
			var arr = hash.split(‘/‘);
			arr.shift();
			cb.apply(self, arr);
		} else {
			self.index && self.go(self.index);
		}
	};

	/**
	 * 开始路由,实际上只是为了当直接访问路由路由地址的时候能够及时调用回调
	 */
	Router.prototype.start = function() {
		var self = this;

		self.reload();
	}

	/**
	 * 获取callback
	 * @return false or callback
	 */
	function getCb(addr, hashList) {
		for(var key in hashList) {
			if(key == addr) {
				return hashList[key]
			}
		}
		return false;
	}
})();

  每次hash的变化我们还可以通过onhashchange事件【核心+精髓】来监听,然后做出相应的处理。。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf8" />
		<script type="text/javascript" src="./router.js"></script>
		<style type="text/css">
		</style>
	</head>

	<body>
		<a href="#!index">go to index</a><br />
		<a href="#!search/SB/shi/ni">go to search</a>
	</body>

	<script type="text/javascript">
		window.onload = function() {
			var router = new Router();
			router.add(‘index‘, function() {
				alert(‘current page: index‘);
			});

			router.add(‘search‘, function(wd, sortType, sortBy) {
				alert(‘current page: search‘ + ‘\nwd: ‘ + wd + ‘\nsortType: ‘ + sortType + ‘\nsortBy: ‘ + sortBy);
			});
			router.setIndex(‘index‘);
			router.start();
		};
	</script>

</html>
时间: 2024-08-07 00:15:35

自己动手写一个前端路由插件的相关文章

动手写一个Remoting测试工具

基于.NET开发分布式系统,经常用到Remoting技术.在测试驱动开发流行的今天,如果针对分布式系统中的每个Remoting接口的每个方法都要写详细的测试脚本,无疑非常浪费时间.所以,我想写一个能自动测试remoting接口的小工具InterfaceTester.而且,当分布式系统中的某个remoting接口出现bug时,该小工具可以提交需要模拟的数据,以便在调试remoting服务的环境中,快速定位和解决bug. InterfaceTester运行起来后的效果如下图: 1.如何使用 (1)首

模拟spring - 动手写一个spring AOP

一.前言 AOP (Aspect Oriented Programing) - 面向切面编程,它主要用于日志记录.性能分析.安全控制.事务处理.异常处理等方面. AOP主要使用JDK的反射和动态代理,AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理包含了目标对象的全部方法,但AOP代理的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法. 动态代理的文章请参考:http://blog.csdn.net/zdp072/ar

死磕 java线程系列之自己动手写一个线程池

欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写的线程池如何测试? 简介 线程池是Java并发编程中经常使用到的技术,那么自己如何动手写一个线程池呢?本文彤哥将手把手带你写一个可用的线程池. 属性分析 线程池,顾名思义它首先是一个"池",这个池里面放的是线程,线程是用来执行任务的. 首先,线程池中的线程应该是有类别的,有的是核心线程,有

我想写一个前端开发工具(一):在npm发布模块

有必要说说我为什么要开始写这个 我最近忙于公司的项目,一直没有抽出时间来写文章.本来想每个月写一片文章,保质保量,无奈上个月没有坚持. 这段时间有点忙,主要是由于公司业务调整,我从原来的广告项目中调整到新业务线的前台页面开发了,和以前一样,还是带着3.4个兄弟姐妹.不同的是以前的项目周期普遍偏长,可以让每个同学有时间从头到尾的把项目吃透,而现在做C端的前台页面往往开发时间非常的短,比如我们就要在1.2个月完成业务线所有前台页面的开发.联调.测试.部署,以及下一步的迭代.由于是从零开始,不存在基于

自己动手写一个FTP客户端

自己用socket写一个FTP客户端,模拟主动被动模式.(先支持LIST命令) # -*- coding: utf-8 -*- import socket, sys, thread, threading def main_sock(daddr, actions, saddr=()):     if saddr:         try:             sc=socket.create_connection(daddr, 3, saddr)             #print "Now

用javascript写一个前端等待控件

前端等待控件有啥新奇的?什么jquery啦,第三方控件啦,好多好多,信手拈来. 因为项目使用了bootstrap的原因,不想轻易使用第三方,怕不兼容.自己写一个. 技术点包括动态加载CSS,javascript的命名空间,所以记录一下. 这个等待控件主要是:进行某个操作前,显示一个信息提示:"数据加载中,请稍候...",操作成功后,在回调函数中将提示消失. 原理是这个等待控件完全由JS动态加进去,包括CSS,页面中并无预先设定. 那么这个CSS怎么动态加载呢?等待控件中,样式使用了cl

死磕 java线程系列之自己动手写一个线程池(续)

(手机横屏看源码更方便) 问题 (1)自己动手写的线程池如何支持带返回值的任务呢? (2)如果任务执行的过程中抛出异常了该怎么处理呢? 简介 上一章我们自己动手写了一个线程池,但是它是不支持带返回值的任务的,那么,我们自己能否实现呢?必须可以,今天我们就一起来实现带返回值任务的线程池. 前情回顾 首先,让我们先回顾一下上一章写的线程池: (1)它包含四个要素:核心线程数.最大线程数.任务队列.拒绝策略: (2)它具有执行无返回值任务的能力: (3)它无法处理有返回值的任务: (4)它无法处理任务

操刀 requirejs,自己动手写一个

前沿 写在文章的最前面 这篇文章讲的是,我怎么去写一个 requirejs . 去 github 上fork一下,顺便star~ requirejs,众所周知,是一个非常出名的js模块化工具,可以让你使用模块化的方式组织代码,并异步加载你所需要的部分.balabala 等等好处不计其数. 之所以写这篇文章,是做一个总结.目前打算动一动,换一份工作.感谢 一线码农 大大帮忙推了携程,得到了面试的机会. 面试的时候,聊着聊着感觉问题都问在了自己的“点”上,应答都挺顺利,于是就慢慢膨胀了.在说到模块化

自己动手写一个iOS 网络请求库的三部曲[转]

代码示例:https://github.com/johnlui/Swift-On-iOS/blob/master/BuildYourHTTPRequestLibrary 开源项目:Pitaya,适合大文件上传的 HTTP 请求库:https://github.com/johnlui/Pitaya 本系列文章中,我们将尝试使用 NSURLSession 技术构建一个自己的网络请求库. NSURLSession 简介 NSURLSession 是 iOS7 引入的新网络请求接口,在 WWDC2013