SPA(单页面应用)设计【自我总结】

一、简介

      SPA即单页面应用(Single Page Application),说简单一点就是把所有操作放在一个页面里,通过JS去实现相关操作,目的之一是为了减轻服务器的压力。关于SPA的详细介绍可看百度百科给出的介绍。 —— [ 百度百科 ]

二、优缺点

1. 优势
1)首先,最大的好处是用户体验,对于内容的改动不需要加载整个页面。这样做好处颇多,因为数据层和UI的分离,可以重新编写一个原生的移动设备应用程序而不用(对原有数据服务部分)大动干戈;
2)单页面Web应用层程序最根本的优点是高效。它对服务器压力很小,消耗更少的带宽,能够与面向服务的架构更好地结合;
**2. 缺点 **
1)对技术要求比较高,开发难度大
2)不利于SEO
3)由于单页是基于JS操作的,因此对浏览器的兼容性比较麻烦(其中大部分问题已基于HTML5有所改进)

三、实现方式

      实现方式有很多,移动端可以使用 vue.js 框架,PC端有使用 angularjs 实现的,我这里使用最原始的 jQuery 实现(主要是我不会 angularjs 哈哈)。

这里准备了5个html页面用于示例说明,分别为:
主页面(一个)
子页面(三个)
子子页面(一个)

主页面

index.html

<script type="text/javascript" src="js/jquery-2.2.3.min.js"></script>
<script type="text/javascript" src="js/index.js" ></script>
........
<div style="float:left;border:1px solid red;margin:20px">
	<p>
		<a href="javascript: void(0);" id="menu1" data-type="CRM" data-url="page1.html">用户管理</a>
	</p>
	<p>
		<a href="javascript: void(0);" id="menu2" data-type="CRM" data-url="page2.html">角色管理</a>
	</p>
	<p>
		<a href="javascript: void(0);" id="menu3" data-type="CRM" data-url="page3.html">权限管理</a>
	</p>
</div>
<div style="float:left;border:1px solid blue;margin:20px" id="main">
	<div style="float:left;border:1px solid red;margin:20px" id="content">
	</div>
</div>

index.js

var params = {
	"id": "123",
	"name": "张三"
}
var cachePage = new Array();

$(function() {
	//添加链接的处理事件
	$("a[data-type='CRM']").click(ajax);
	//添加popstate事件
	$(window).on("popstate", function() {
		var presentName = history.state && history.state.presentName;
		if(presentName) {
			console.log(presentName);
			$("#main").html('');
			var isLast = true;
			$.each(cachePage, function(k, v) {
				if(v.presentName == presentName) {
					$("#main").append(v.presentPage);
					isLast = false;
					return false;
				}
			});
			console.log(isLast + "++++++++++");
		}
	});
});

/**
 1. 核心
 2. @param {Object} event
 3. @param {Object} isPopstate
 */
function ajax(event, isPopstate) {
	var url = $(this).attr('data-url');
	var browserPath = location.href.split("?");
	// 修改当前状态信息(修改历史记录)
	// 即将即将替换的页面信息更新到集合中
	if(browserPath.length > 1) {
		var urlParams = browserPath[1].split('=');
		if(urlParams.length > 1 && urlParams[0] == 'name') {
			// 获取当前状态下的 presentName
			var presentName = history.state.presentName;
			console.log(presentName + "----");
			var lastHtml = $("#content").clone(true);
			var lastPage = {
				'presentName': presentName,
				'presentPage': lastHtml
			};
			for(var i = 0, flag = true, len = cachePage.length; i < len; flag ? i++ : i) {
				if(cachePage[i] && cachePage[i].presentName == presentName) {
					cachePage.splice(i, 1);
					flag = false;
				} else {
					flag = true;
				}
			}
			cachePage.push(lastPage);
		}
	}

	$.ajax({
		type: "get",
		url: url,
		async: false,
		success: function(data) {
			$("#content").html(data);
		}
	});
	var title = this.id;
	document.title = title;
	// 保存当前记录【注:该记录只保存了页面初次信息,后续页面所做操作信息无法保存】
	if(!isPopstate) {
		var presentName = title + "_" + new Date().getTime();
		console.log("哈哈:" + presentName + "----");
		var presentHtml = $("#content").clone(true);
		var presentPage = {
			'presentName': presentName,
			'presentPage': presentHtml
		};
		console.log("集合大小:" + cachePage.length);
		cachePage.push(presentPage);
		console.log("集合长度:" + cachePage.length);
		history.pushState({
			presentName: presentName // 当前
		}, "", location.href.split("?")[0] + "?name=" + presentName);
	}
}

子页面

  1. page1.html
<body>
   	<h1 style="color: red;">第一个页面</h1>
   	<input type="text" name="text01" id="text01" class="text-info" value=""/>
   	<input type="button" class="btn-success" onclick="test()" value="测试"/>
   	<div id="test1"></div>
   </body>
   <script type="text/javascript">
   	function test() {
   		alert(params.id + "----" + params.name);
   	}
   	$(function(){
   		var array = new Array();
   		array.push({'url': 'page1.1.html', 'text': '员工管理~'});
   		
   		var ahtmls = initChildA(array);
   		$('#test1').append(ahtmls);
   		$("#test1 a[data-type='CRM']").click(ajax);
   	});
   	function initChildA(params) {
   		var ahtmls = '';
   		var idPrefix = '';
   		var query = location.href.split("?")[1];
   		var idStr = query.split("=")[1];
   		if (idStr.split('-').length > 0) {
   			idPrefix = idStr.split('-')[0];
   		} else {
   			idPrefix = idStr;
   		}
   		$.each(params, function(k, v) {
   			ahtmls += '<a href="javascript: void(0);" id="' + idPrefix + '-' + (k + 1) + '"';
   			ahtmls += ' data-type="CRM", data-url="' + v.url + '">' + v.text + '</a>';
   		});
   		
   		return ahtmls;
   	}
   </script>
  1. page2.html
<body>
   	<h1 style="color: blue;">第二个页面</h1>
   	<h1 style="color: blue;">第二个页面</h1>
   	<input type="button" class="btn-info" value="返回" onclick="goBack()"/>
   </body>
   <script type="text/javascript">
   	function goBack() {
   		window.history.go(-1);
   	}
   </script>
  1. page3.html
<body>
   	<h1 style="color: blueviolet;">第三个页面</h1>
   	<h1 style="color: blueviolet;">第三个页面</h1>
   	<h1 style="color: blueviolet;">第三个页面</h1>
   	<a href="javascript: void(0);" class="btn-link" onclick="javascript :history.back(-1);">返回上一页</a>
   </body>

子子页面

page1.1.html

<body>
	<h1 style="color:chartreuse;">第一个页面的子页面</h1>
	<h1 style="color:chartreuse;">第一个页面的子页面</h1>
	<h1 style="color:chartreuse;">第一个页面的子页面</h1>
	<a href="javascript: void(0);" class="btn-link" onclick="javascript :history.back(-1);">返回上一页</a>
</body>

到此为止基本上是实现了单页面操作,这个例子基本实现后退时保留历史操作记录(不刷新页面)。
上述示例未解决的问题是最后点击的那个页面,无法记录下操作后页面的数据

在测试过程中,发现了一个很有意思的事情,操作流程如下:

  1. 依次点击:page1 --> page2
  2. 返回(按钮/浏览器均可)page1
  3. 再点击 page3,然后连续返回
  4. 预想结果为:page3 --> page1 –> page2 --> page1 --> index
  5. 而实际结果为:page3 --> page1 --> index

为此我还特意做了一个多页面的例子,发现也是一样的效果,后来我猜想是因为浏览器在返回page1后再点击,浏览器会更新之前page1对应的那条历史记录。

有谁知道具体原因,欢迎在下面评论告诉我

使用JQ来实现单页面应用还是比较费劲,推荐使用Vue来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值