天天看點

二十七、HTML5單頁架構View.js介紹 - 視圖切換動畫

不需要 Npm 的單頁應用架構:

View.js - http://view-js.com

視圖切換動畫,是指活動視圖發生變化,從一個視圖切換至另外一個視圖的過程中展現給使用者的動畫效果。

我們來看兩個例子:

動畫1(點選體驗)

二十七、HTML5單頁架構View.js介紹 - 視圖切換動畫

動畫2(點選體驗)

二十七、HTML5單頁架構View.js介紹 - 視圖切換動畫

開發者也可以選擇不應用動畫,效果如下圖所示:

二十七、HTML5單頁架構View.js介紹 - 視圖切換動畫

通過對比,我們可以清晰地觀察到:動畫點綴會使得視圖切換生動許多。那麼,我們該如何開發視圖切換動畫呢?

通常情況下,開發者需要按照如下流程完成視圖切換動畫的開發:

  1. 使用css,借助 animation、transition 等屬性建立視圖離開動畫、視圖進入動畫
  2. 『有條件地』引用動畫并确定動畫播放時長
  3. 在頁面就緒時調用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;
}

           

其中

  1. fadeOut

    hideToLeft

    hideToRight

    定義了視圖的離開動畫,亦即視圖由活動狀态變為非活動狀态時要執行的動畫;
  2. fadeIn

    showFromRight

    showFromeLeft

    定義了視圖的進入動畫,亦即視圖由非活動狀态變為活動狀态時要執行的動畫;
  3. .view.hideToLeft

    .view.hideToRight

    定義了視圖離開動畫的播放時機:在視圖根節點DOM元素含有對應樣式類時播放動畫;
  4. .view.showFromLeft

    .view.showFromeRight

    定義了視圖進入動畫的播放時機:在視圖根節點DOM元素含有對應樣式類時播放動畫;

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在何時播放什麼動畫:

  1. 壓入堆棧時,源視圖向左滑動隐藏,目标視圖從右向左顯示
  2. 彈出堆棧時,源視圖向右滑動隐藏,目标視圖從左向右顯示

其中,『壓入堆棧式』的視圖切換可能由如下幾種行為觸發:

  1. 開發者調用API:

    View.navTo({String} targetViewId:目标視圖ID)

  2. 開發者調用API:

    View.forward()

    - 向前查閱視圖,等同于

    history.forward()

  3. 使用者點選聲明有

    data-view-rel

    屬性的元素,且

    data-view-rel-type

    取值為

    nav

    (沒有聲明

    data-view-rel-type

    屬性時,預設為

    nav

  4. 使用者點選浏覽器中的前進按鈕

『替換堆棧式』的視圖切換則由如下幾種行為觸發:

  1. 開發者調用API:

    View.changeTo({String} targetViewId:目标視圖ID)

  2. 使用者點選聲明有

    data-view-rel

    屬性的元素,且

    data-view-rel-type

    取值為

    change

    (沒有聲明

    data-view-rel-type

    屬性時,預設為

    nav

有關視圖跳轉的詳細介紹,請查閱 視圖跳轉(一) 和 視圖跳轉(二)。

[第一篇]

[上一篇 - 視圖回退顯示] [下一篇 - 識别浏覽器的前進與後退]

繼續閱讀