1. 程式人生 > >SPA(單頁面應用)設計【自我總結】

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>
  2. 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>
  3. 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對應的那條歷史記錄。

有誰知道具體原因,歡迎在下面評論告訴我