SPA(單頁面應用)設計【自我總結】
阿新 • • 發佈:2019-01-30
一、簡介
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);
}
}
子頁面
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>
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>
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對應的那條歷史記錄。
有誰知道具體原因,歡迎在下面評論告訴我