基于dom的前端路由简单实现

作者: 麦草CMS 日期: 2019/03/03 12:25:23

前端路由是vue框架特色之一。用过的人都会对之爱不释手。单页web应用(spa)现在非常盛行,构建spa就要会涉及前端路由的概念。


前端路由的就是“劫持”网页链接,然后用利用ajax接收到的后端数据构建dom节点替换指定的dom节点,并且同时改变浏览器地址栏的页面地址,做到更新页面内容和页面地址而不刷新页面。前端路由的基本原理是为页面链接绑定click事件;click事件处理函数利用ajax从后端接收数据构建dom节点替换指定的dom节点更新页面内容,同时用location.hash或HTML5新增的浏览器history.pushState,history.replaceState接口改变页面地址;这样就做到不刷新页面而达到了刷新页面的效果。


vue2的前端路由是基于虚拟DOM的。今天我就来实现一个简单的javascript操作DOM的前端路由。


javascript代码router.js:

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 
	(typeof define === 'function' && define.amd ? define(factory) : (global.Router = factory()));
}(this, (function(){
	'use strict';
	//var isListened = false;
	var index = 0;
	
	//History类
	function History(){
	}
	
	var HTML5HistorySupport = "pushState" in history && "replaceState" in history;
	//HTML5History类
	function HTML5History(routes, options){
		var self = this, state = history.state, route, routes, routeNode, stateObj, content;
		//继承History类
		History.call(this);
		this.index = 0;
		for(var i = 0, len = routes.length; i < len; i++){
			route = routes[i];
			routeNode = document.querySelector(route.node);
			MyCMS.event.addEvent( routeNode, "click", function(evt){ handler( evt, route, self);});
		}
		stateObj = {containers : [route.container], contents : [document.querySelector(route.container).innerHTML]};
		state = JSON.stringify(stateObj);
		history.replaceState(state, document.title, location.href);
		function handler(evt, route, self){
			var title, url, elem;
			MyCMS.event.cancelBubble(evt);
			MyCMS.event.preventDef(evt);
			elem = MyCMS.event.getElement(evt);
			url = elem.href;
			if(elem.nodeName == "A" && elem.hasAttribute("data-route")){
				content = document.querySelector(route.container).innerHTML;
				if(index === 0){
					stateObj = {containers : [route.container], contents : [index/*content*/]};
					state = JSON.stringify(stateObj);
					history.pushState(state, document.title, url);
					index++;
				}else{
					stateObj = {containers : [route.container], contents : [index/*content*/]};
					state = JSON.stringify(stateObj);
					history.pushState(state, document.title, url);
					index++;
				}
			}
		}
		window.addEventListener("popstate", function(){
			var stateObj = JSON.parse(history.state), s = stateObj.containers, c = stateObj.contents;
			for(var i = 0, leng = s.length; i < leng; i++){
				document.querySelector(s[i]).innerHTML = c[i];
			}
		});
	}
	//HTML5History.prototype.support = "pushState" in history && "replaceState" in history;
	HTML5History.prototype.push = function (){
		var state, title, url;
		history.pushState(state, title, url);
	};
	HTML5History.prototype.replace = function (){
		var state, title, utl;
		history.replaceState(state, title, url);
	};
	HTML5History.prototype.go = function (n){
		history.go(n);
	};
	
	return HTML5History;
})));


html页面代码router.html:

<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Author" content="麦草CMS">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>
  <script src="router.js"></script>
 </head>
 <body>
  <div id="nav">
  <a data-route href="router.html?id=1">第1项</a>
  <a data-route href="router.html?id=2">第2项</a>
  <a data-route href="router.html?id=3">第3项</a>
  <a data-route href="router.html?id=4">第4项</a>
  <a data-route href="router.html?id=5">第5项</a>
  <a data-route href="router.html?id=6">第6项</a>
  </div>
  <div id="container">初始
  </div>
  <script>
  var router = new Router([{node: "#nav", container: "#container"}]);
  </script>
 </body>
</html>


当然,这里仅仅是一个思路。整体换需要ajax的配合。

我还说什么呢?
0.0018701553344727