不需要 Npm 的單頁應用架構:
View.js - http://view-js.com
視圖切換動畫,是指活動視圖發生變化,從一個視圖切換至另外一個視圖的過程中展現給使用者的動畫效果。
我們來看兩個例子:
動畫1(點選體驗)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmL3YzM5MTO1gTM4EzMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
動畫2(點選體驗)
開發者也可以選擇不應用動畫,效果如下圖所示:
通過對比,我們可以清晰地觀察到:動畫點綴會使得視圖切換生動許多。那麼,我們該如何開發視圖切換動畫呢?
通常情況下,開發者需要按照如下流程完成視圖切換動畫的開發:
- 使用css,借助 animation、transition 等屬性建立視圖離開動畫、視圖進入動畫
- 『有條件地』引用動畫并确定動畫播放時長
- 在頁面就緒時調用View.js提供的
方法,以設定動畫的『播放觸發器』
View.setSwitchAnimation
以下是動畫2的源碼(已在注釋中較長的描述各個步驟的執行)。
HTML
<!-- 視圖1的DOM骨架 -->
<section id = "page1" data-view = "true" data-view-default = "true" >
<header>
<span class = "nav-back" data-view-rel = ":back"></span>
Page 1
</header>
<h1>This is page 1.</h1>
<div data-view-rel = "page2" class = "btn">Navigate to page 2.</div>
</section>
<!-- 視圖2的DOM骨架 -->
<section id = "page2" data-view = "true">
<header>
<span class = "nav-back" data-view-rel = ":back"></span>
Page 2
</header>
<h1>This is page 2.</h1>
<div data-view-rel = "page3" class = "btn">Navigate to page 3.</div>
</section>
<!-- 視圖3的DOM骨架 -->
<section id = "page3" data-view = "true">
<header>
<span class = "nav-back" data-view-rel = ":back"></span>
Page 3
</header>
<h1>This is page 3.</h1>
<div data-view-rel = ":default-view" class = "btn">Navigate to page 1.</div>
</section>
DOM骨架定義了視圖的基本結構。開發視圖骨架是使用View.js開發視圖的第一要務。
CSS
/**
* 定義動畫
*/
@keyframes hideToLeft{
from{transform: translate3d(0, 0, 0); opacity: 1;}
to{transform: translate3d(-50%, 0, 0); opacity: 1;}
}
@keyframes showFromRight{
from{transform: translate3d(100%, 0, 0); opacity: 1;}
to{transform: translate3d(0, 0, 0); opacity: 1;}
}
@keyframes hideToRight{
from{transform: translate3d(0, 0, 0); opacity: 1;}
to{transform: translate3d(100%, 0, 0); opacity: 1;}
}
@keyframes showFromLeft{
from{transform: translate3d(-50%, 0, 0); opacity: 1;}
to{transform: translate3d(0, 0, 0); opacity: 1;}
}
/**
* 視圖容器水準居中
*/
[data-view-container]{
position: relative;
margin: 0 auto;
}
/**
* 所有視圖重疊在一起,預設都不顯示
*/
*[data-view=true] {
opacity: 0;
z-index: 0;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
overflow: auto;
-webkit-overflow-scrolling: touch;
background: #F3F3F3;
box-shadow: 0 0 70px rgba(0, 0, 0, 0.3);
}
/**
* 視圖隐藏時要呈現的半透明黑色蒙層。預設不顯示
*/
*[data-view=true]:before{
opacity: 0;
content: "";
display: none;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
}
/**
* 活動視圖可見
*/
*[data-view=true].active {
opacity: 1;
z-index: 1;
}
/**
* 有條件地引用動畫
*/
/* 視圖含有hideToLeft樣式類時播放hideToLeft動畫 */
.view.hideToLeft{
animation: hideToLeft 0.6s ease-out;
}
/* 視圖向左隐藏時逐漸顯示半透明黑色蒙層 */
.view.hideToLeft:before{
display: block;
animation: fadeIn 0.6s linear;
}
/* 視圖含有showFromLeft樣式類時播放showFromLeft動畫 */
.view.showFromLeft{
animation: showFromLeft 0.6s ease-out;
}
/* 視圖取消隐藏時逐漸關閉半透明黑色蒙層 */
.view.showFromLeft:before{
display: block;
animation: fadeOut 0.6s linear;
}
/**
* 視圖含有hideToRight樣式類時播放hideToRight動畫。
* z-index要比活動視圖的1更高,進而使其不會被活動視圖覆寫
*/
.view.hideToRight{
z-index: 2;
animation: hideToRight 0.6s ease-out;
}
/* 視圖含有showFromRightn樣式類時播放showFromRightn動畫 */
.view.showFromRight{
animation: showFromRight 0.6s ease-out;
}
其中
,
fadeOut
,
hideToLeft
定義了視圖的離開動畫,亦即視圖由活動狀态變為非活動狀态時要執行的動畫;
hideToRight
,
fadeIn
,
showFromRight
定義了視圖的進入動畫,亦即視圖由非活動狀态變為活動狀态時要執行的動畫;
showFromeLeft
,
.view.hideToLeft
定義了視圖離開動畫的播放時機:在視圖根節點DOM元素含有對應樣式類時播放動畫;
.view.hideToRight
,
.view.showFromLeft
定義了視圖進入動畫的播放時機:在視圖根節點DOM元素含有對應樣式類時播放動畫;
.view.showFromeRight
JS
;(function(){
var timer;
/**
* 動畫持續時長,需要與css中定義的動畫時長一緻
* @type {number}
*/
var animationDuration = 600;
/**
* 清除給定DOM元素上聲明的動畫樣式
* @param {HTMLElement} obj
*/
var clear = function(obj){
if(!obj)
return;
"hideToLeft, showFromRight, hideToRight, showFromLeft".split(/\s*,\s*/).forEach(function(className){
obj.classList.remove(className);
});
};
/**
* @param {HTMLElement} srcElement 視圖切換時,要離開的目前視圖對應的DOM元素。可能為null
* @param {HTMLElement} tarElement 視圖切換時,要進入的目标視圖對應的DOM元素
* @param {String} type 視圖切換方式
* @param {Function} render 渲染句柄
*/
View.setSwitchAnimation(function(srcElement, tarElement, type, render){
/**
* 動畫播放前清除可能存在的動畫樣式
*/
clear(srcElement);
clear(tarElement);
/**
* 調用View.js傳遞而來的渲染句柄,完成活動視圖的切換,包括:
* 1. 視圖參數的傳遞
* 2. 活動視圖樣式類的切換
* 3. leave,ready、enter等事件的觸發
*/
render();
var isNav = type === View.SWITCHTYPE_VIEWNAV,
isChange = type === View.SWITCHTYPE_VIEWCHANGE,
isHistoryBack = type === View.SWITCHTYPE_HISTORYBACK,
isHistoryForward = type === View.SWITCHTYPE_HISTORYFORWARD;
if(isHistoryForward || isNav){
/**
* 視圖切換動作是“壓入堆棧”的方式(浏覽器前進,或代碼觸發)
*/
srcElement.classList.add("hideToLeft");
tarElement.classList.add("showFromRight");
}else{
/**
* 視圖切換動作是“彈出堆棧”的方式(浏覽器後退)
*/
srcElement.classList.add("hideToRight");
tarElement.classList.add("showFromLeft");
}
/**
* 動畫播放完成後清除動畫樣式
*/
clearTimeout(timer);
timer = setTimeout(function(){
clear(srcElement);
clear(tarElement);
}, animationDuration);
});
})();
其中
View.setSwitchAnimation()
用于向View.js提供『播放觸發器』,告知View.js在何時播放什麼動畫:
- 壓入堆棧時,源視圖向左滑動隐藏,目标視圖從右向左顯示
- 彈出堆棧時,源視圖向右滑動隐藏,目标視圖從左向右顯示
其中,『壓入堆棧式』的視圖切換可能由如下幾種行為觸發:
- 開發者調用API:
View.navTo({String} targetViewId:目标視圖ID)
- 開發者調用API:
- 向前查閱視圖,等同于
View.forward()
history.forward()
- 使用者點選聲明有
屬性的元素,且
data-view-rel
取值為
data-view-rel-type
(沒有聲明
nav
屬性時,預設為
data-view-rel-type
)
nav
- 使用者點選浏覽器中的前進按鈕
『替換堆棧式』的視圖切換則由如下幾種行為觸發:
- 開發者調用API:
View.changeTo({String} targetViewId:目标視圖ID)
- 使用者點選聲明有
屬性的元素,且
data-view-rel
取值為
data-view-rel-type
(沒有聲明
change
屬性時,預設為
data-view-rel-type
)
nav
有關視圖跳轉的詳細介紹,請查閱 視圖跳轉(一) 和 視圖跳轉(二)。
[第一篇]
[上一篇 - 視圖回退顯示] [下一篇 - 識别浏覽器的前進與後退]