在Web App和Hybrid App橫行的時代,為了擁有更好的使用者體驗,單頁面應用順勢而生,單頁面應用簡稱`SPA`,即Single Page Application,就是隻有一個HTML頁面的應用程式,應用中所有的檢視都包含在這個HTML頁面中,並透過JavaScript控制相關檢視的顯示和隱藏,這種模式可以讓使用者在Web App感受Native App的速度和流暢。本篇文章的目的就是教你如何來快速的構建一個H5單頁面切換骨架。
頁面設計
在構建SPA應用時,首先要確定你的應用需要包含哪些檢視,在這裡,為了能夠說明問題,我們只需要構建三個檢視,即 首頁、列表頁面和列表詳情頁面。 這三個頁面的邏輯關係是:
- 程式啟動,預設進入首頁
- 點選首頁的按鈕切換到列表頁面
- 點選列表頁面的按鈕切換到列表詳情頁面
- 點選返回按鈕或物理返回鍵能夠回到上一頁。
首先我們來看一下核心的HTML程式碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<body> <div class = "pageview" style= "background: #3b76c0" id= "-main-view" > <h3>首頁</h3> <div title= "-list-view" class = "right-arrow" ></div> </div> <div class = "pageview" style= "background: #58c03b;display: none" id= "-list-view" > <h3>列表頁面</h3> <div class = "left-arrow" ></div> <div title= "-detail-view" class = "right-arrow" ></div> </div> <div class = "pageview" style= "background: #c03b25;display: none" id= "-detail-view" > <h3>列表詳情頁面</h3> <div class = "left-arrow" ></div> </div> </body> |
class=`pageview`的div容器所包含的就是一個獨立的檢視頁面,在body中共有3個這樣的div,需要注意的是,第2、3個div都設定了style=`display:none`,唯獨第1個檢視沒有設定,這樣做的目的就是讓程式啟動時預設顯示首頁。
在這段程式碼中,用一個通用的CSS類來描述每一個檢視的樣式以及切換效果,這個類就是`pageview`, 我們先看看pageview是如何定義的:
1
2
3
4
5
6
7
8
9
|
.pageview{ position: absolute; left: 0; top:0; width: 100%; height: 100%; overflow: hidden; -webkit-transition: 0.4s ease- out -webkit-transform; } |
在這裡,檢視頁面需要設定成絕對定位,並且和父容器等寬等高,這樣檢視才能夠平滑的進行切換,另外還需要設定頁面切換的過渡效果,我們使用CSS3的transition屬性, 具體的引數就不在這裡做過多的講解了,大家應該都明白的。這個樣式類所產生的效果是:當改變-webkit-transform的值時,頁面會以樣式中定義的過渡效果進行平移,持續時間是0.4s. 到此為止,主要的頁面設計已經完成了。
邏輯控制
要實現頁面切換,就要控制兩個頁面同時平移,即當前頁面不斷的離開螢幕,新的頁面不斷的進入螢幕。為了方便描述,我們把原來的頁面叫做`currentView`,把新的頁面叫做`applyView`,即申請進入的檢視。如果用transform來描述的話,currentView 需要從原來的0% 平移到-100%,即頁面向左平移了一個頁面寬度的距離,與此同時,appyView需要從原來的100% 平移到0%,剛好佔領currentView原來的位置,當然在平移之前,我們需要設定好currentView和applyView的初始位置,分別需要設定成0%和100%。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 頁面向左平移 var currentViewStart = "translateX(0%)" , // currentView初始位置 applyViewStart = "translateX(100%)" , // applyView初始位置 currentViewEnd = "translateX(-100%)" , // currentView的最終位置 applyViewEnd = "translateX(0%)" ; // applyView最終位置 // 頁面向右平移 if (direction == "right" ) { currentViewStart = "translateX(0%)" ; applyViewStart = "translateX(-100%)" ; currentViewEnd = "translateX(100%)" ; applyViewEnd = "translateX(0%)" } |
我們知道,透過JS操作就需要獲取頁面的DOM物件,為了減少DOM的查詢,在頁面載入時,我們將所有需要用到的頁面物件一次性查詢出來,並以鍵值對的形式儲存到Map物件中,當需要使用時,只需要根據key來獲取即可。
1
2
3
4
5
6
7
8
9
|
//初始化執行 initViewPool:function(){ var views = document.querySelectorAll( ".pageview" ); // 透過call使用陣列的forEach來遍歷NodeList Array.prototype.forEach.call(views,function(item){ // viewPool是一個全域性物件 viewPool[item.id] = item; // 將DOM的id作為鍵 }); } |
下面我們將透過JS來控制頁面的切換效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// 獲取當前頁面的DOM物件 var currentView = viewPool[currentViewId]; // 獲取新頁面的DOM物件 var applyView = viewPool[pageId]; // 設定新頁面的初始位置 applyView.style.webkitTransform = applyViewStart; // 設定當前頁面的初始位置 currentView.style.webkitTransform = currentViewStart; // 設定新頁面顯示 applyView.style.display = "" ; var t1 = setTimeout(function() { // 當設定最終位置時,頁面就會以過渡效果平移到最終位置 applyView.style.webkitTransform = applyViewEnd; currentView.style.webkitTransform = currentViewEnd; },200); var t2 = setTimeout(function() { // 400ms後,頁面平移結束,設定currentView為隱藏 currentView.style.display = "none" ; // 將新頁面設定為當前頁面 currentViewId = pageId; if (direction === 'left' ) { window.location.hash = currentViewId.substring(1); } window.clearTimeout(t1); window.clearTimeout(t2); },600); |
在這裡有一個重要的操作就是:一定要將設定最終位置的操作放到定時器中,即t1, 這是因為當頁面被設定了初始位置後,需要一定的時間來`渲染`這個樣式,第2個定時器是為了等待動畫執行完畢後進行相關的操作,比如設定當前頁面,設定hash,清除定時器等。當這段程式碼被執行時,頁面就會以設定的效果進行平滑的移動,最終,當前頁面被隱藏,新頁面被設定為當前頁面顯示到螢幕中央,這樣就完成了一次單頁面切換效果。
支援物理鍵返回
既然是單頁面切換,就不得不提另外一個問題,那就是物理返回鍵操作。其實,單頁面切換隻是頁面的顯示和隱藏操作,僅此而已,並不是真正意義上的hash跳轉,而物理鍵返回實際上是監聽瀏覽器的hash變化,因此為了讓單頁面能夠支援物理鍵返回操作,我們需要模擬瀏覽器的hash變化,即當一個新頁面進入時,給當前地址加上一個#hash 的標識,當點選物理返回鍵的時候,這個hash值會發生變化(回退到上一個hash),與此同時也會觸發一個hashchange事件,當監聽到hash變化時,我們就透過JS切換到上一個hash對應的頁面,這樣就實現了物理返回鍵的效果。
1
2
3
4
|
if (direction === 'left' ){ //當進入到新頁面時,設定當前hash的值為當前頁面的id window.location.hash = currentViewId.substring(1); } |
監聽hash變化的處理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var that = this ; window.addEventListener( "hashchange" , function () { //當點選返回鍵時,hash會回退到上一頁的hash值 //獲取上一頁的hash值,並轉化為對應view的id var id = window.location.hash.replace( "#" , "-" ); // 判斷當前頁面不是首頁, // 並且觸發的瀏覽器的`back`操作,即點選返回鍵,因為頁面前進的時候也會發生hash變化 if (currentViewId != "-main-view" && id != currentViewId) { id = id || "-main-view" ; //如果上一頁是首頁,則hash為空,這時需要補上對應的id //呼叫forward方法從當前頁面切換到上一頁 that.forward(id, "right" ); } }, false ); |
以上便是單頁面切換的基本思路,對應的完整示例程式碼已上傳至 Github: https://github.com/git-onepixel/h5spa, 你可以下載完整程式碼進行除錯和學習,如果需要檢視效果演示,請點選或使用微信掃一掃下面的二維碼進行訪問: