為你的Web程序加個啟動畫面
.Net開發者一定熟悉下面這個畫面:
這就是宇宙***IDE Visual Studio的啟動畫面,學名叫Splash Screen(或者Splash Window)。同樣,Javar們一定對Eclipse的啟動畫面不會陌生。不只是IDE,很多桌面程序都會有這個Splash 窗口,在程序進行初始化時顯示。
這方面做得最贊的非Adobe旗下的設計類軟件莫數了,畢竟是搞藝術出身的啊。博主從PS 8.0用起,每次升級新版本激動的不是新功能,首先是激動新的啟動畫面。下圖是***CC版PS的Splash Screen。視覺效果震撼的一逼。。張牙舞爪的,無出其右。
啟動畫面也不是桌面程序所獨有,完全可以在我們的網頁中實現。并且隨著時間的推移,現在Web應用越來紛繁復雜,加載也是很費時的,一個Splash Screen就顯得很有必要了不是么。
比如谷哥的Gmail,要是全屏運行,就一個原生App的感覺。
下面我們就來為我們的Web應用加上Gmail一樣的Splash Screen。程序可以很渣,若表面功夫到位了同樣可以顯得高端大氣上檔次。
進度的獲取
展示靜態圖片還好,如果你的啟動界面要顯示程序進行的進度的話,一個很棘手的問題來了,如何獲取進度。經過大量的調研(寫過論文的同學都知道,類似'經過大量實驗表明…'的表述其實很有可能是只做了一次實驗就開始寫結論了)我發現,沒有辦法獲取一個頁面的實際下載進度!當然,不排除我孤陋寡聞,如果你知道這樣的方法請告訴我。
對于頁面中的異步操作,倒是可以監聽到進度的。但也得分情況。HTML5規范中,Ajax多了個progress事件,通過它可以獲取異步操作的完成情況,但前提是event.lengthComputable屬性為真是才管用。也就是說有些請求的結果我們是可以知道大小的,但更多時候服務器返回的內容的大小是不確定的,這種情況下即使你監聽了progress事件也無法獲取真實的操作進度。
既然如此,那我們就不要那么死磕,具體進行到百分之幾意義不大,我們的目的是提高用戶體驗,在用戶等待的這個過程中有東西可看,或者有一個活著的會動的東西表明程序還在跑而不是出錯了卡死了。所以給用戶展示一個會動的進度條即可(我相信大多數帶進度條的程序也是這么干的),直到頁面全部加載完成時把進度條托到100%。
插曲:在我探索如何獲取頁面真實下載進度的過程中,研究了pace.js的代碼,一個做得非常棒的頁面加載進度插件,發現他內部也是這么干的,頁面上顯示的進度并不真實返回頁面加載的實現進度,只是不斷的增加而以,等頁面加載完了再拖到100%。當然該庫寫得比較完善,處理了各種情況比如ajax,web socket等。另外就是Gmail,經過大量(也有可能只有兩三次,請不必太認真)的刷新頁面嘗試之后,我發現個規律,它的進度條會一路跑到一個點然后停下來,然后再一路跑到終點!之前的結論。(不過谷歌擁有牛逼烘烘的工程師,不排除他用了啥高科技算法在里面能夠精確地返回頁面加載的進度。Anyway, 如果我這里的結論錯,請別太認真找我麻煩)
Nprogress
方便起見,這里使用nprogress這個JS庫來顯示動畫。它提供了很方便的幾個API可供我們使用。
NProgress.start() — 啟動進度條
NProgress.set(0.4) — 將進度設置到具體的百分比位置
NProgress.inc() — 少量增加進度
NProgress.done() — 將進度條標為完成狀態
定義我們的Splash Screen
好的,思路出來了下面我們就開始毫無技術含量的施工。
具體來說,首先頁面只顯示我們預先定義好的Splash Screen,它要占滿整個屏幕且z-index設為頁面中***。
這里直接借用Juri 發表在他博客中的代碼,不過我們使用我之前一篇博文《前端冷知識集錦》可提到的技巧,將HTML代碼存放在一個script標簽中。
- <script type="text" id="splash-template">
- <div class="splash card">
- <div role="spinner">
- <div class="spinner-icon"></div>
- </div>
- <p class="lead" style="text-align:center">不要回來,馬上走開...</p>
- <div class="progress">
- <div class="mybar" role="bar">
- </div>
- </div>
- </div>
- </script>
這個splash screen會在HTML加載好之后***時間顯示。接下來就可以這樣做了,在頁面最開始調用 Nprogress.start()啟動進度條,而在這個splash screen下方遮住的頁面中,繼續我們程序的初始化,做其他一些非常耗時的操作等。比如你想象一下Gmail,最開始可能頁面只有顯示進度條那些基本的HTML和JS代碼,然后需要向服務器請求大量的郵件信息,數據接收完后,再組織成HTML生成郵件列表append到頁面,但這個過程因為被進度條擋住了,所以我們看不見。等一切就緒,再調用Nprogress.done()將進度條隱藏。這時你看到的就是一個完整的頁面了。
事件的順序
window.onload事件是在整個頁面加載完成,包括其中所有圖片,iframe等。所以,可以確定在這個事件里面把進度搞到100%是沒有問題且邏輯正確的。
確定了何時結束再來看何時開始。既然我們一開始就要顯示Splash Window且操作之前定義好的splash screen模板,意思就是說再怎么早開始也得等我們splash screen部分的HTML加載完成之后再進行吧。所以,得到的結論就是把進度條開始的代碼放在這部分HTML代碼之后,但這種HTML中插JS的做法很不好,所以***決定還是放在$(document).ready()里面,因為這個事件是在頁面HTML加載完后觸發的,但只是DOM,不包括其他比如上面提到的圖片,iframe等,所以它是比window.onload先觸發的。
所以在頁面的head標簽里面加入以下代碼:
- $(function() {
- NProgress.configure({
- template: $('#splash-template').html()
- });
- NProgress.start();
- });
- $(window).load(function() {
- NProgress.done();
- })
實際應用中更科學的做法其實應該是這樣的,頁面只有關于進度條的代碼,程序的內容全部通過Ajax填充到頁面,然后在頁面中監視所有Ajax的返回情況。
模擬耗時的操作
一切就緒了,但需要解決一個事情就是如何模擬耗時的操作。我們現在弄的這個例子它不費時,無法看到緩慢的加載效果,并且本地測試,放上幾十張圖片都會很快就完事。
當然可以用setTimeout來達到目的,但不太科學吧,還是要弄得真實點。于是我們在頁面放一個iframe,從其他網站引用頁面,這樣多少會有些加載的時間。
所以這個例子***的代碼差不多是這樣的了:
HTML:
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="description" content="">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>splash screen example</title>
- <link rel="stylesheet" href="nprogress.css">
- <link rel="stylesheet" href="main.css">
- <script src="jquery.min.js"></script>
- <script src="nprogress.js"></script>
- <script type="text/javascript">
- $(function(){
- NProgress.configure({
- template: $('#splash-template').html()
- });
- NProgress.start();
- });
- $(window).load(function(){
- NProgress.done();
- })
- </script>
- </head>
- <body>
- <script type="text" id="splash-template">
- <div class="splash card">
- <div role="spinner">
- <div class="spinner-icon"></div>
- </div>
- <p class="lead" style="text-align:center">不要回來,馬上走開...</p>
- <div class="progress">
- <div class="mybar" role="bar">
- </div>
- </div>
- </div>
- </script>
- <iframe id="iframe" style="width: 100%; height: 660px;" src="http://wayou.github.io/SlipHover/" frameborder="0"></iframe>
- </body>
- </html>
加入些美化的樣式:
CSS:
- html,body,iframe{
- margin: 0;
- padding: 0;
- }
- #nprogress{
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: #f7f7f7;
- z-index: 999;
- }
- .spinner-icon{
- display: none!important;
- }
- .splash {
- position:absolute;
- top:40%;
- left:0;
- right:0;
- margin: auto;
- }
- .splash img {
- display: block;
- margin-left: auto;
- margin-right: auto;
- height: 100px;
- width: 100px;
- }
- .card {
- background-color: #f7f7f7;
- padding: 20px 25px 15px;
- margin: 0 auto 25px;
- width: 380px;
- }
- .mybar {
- background: #29d;
- height:10px;
- }
- .progress {
- height: 10px;
- overflow: hidden;
- }
現在可以運行頁面查看效果了。好了,就這么多。效果預覽請點我
Reference
- Intercept Page Load: https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Intercepting_Page_Loads
- Gmail-style progress bar when page is loading http://stackoverflow.com/questions/8020929/gmail-style-progress-bar-when-page-is-loading
- http://www.gayadesign.com/scripts/queryLoader/
- https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress
- http://api.jquery.com/jQuery.ajax/
- http://stackoverflow.com/questions/15328275/show-progressbar-while-loading-pages-using-jquery-ajax-in-single-page-website
- http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/
- http://github.hubspot.com/pace/
- http://onextrapixel.com/examples/youtube-like-ajax-loading-bar/
原文鏈接:http://www.cnblogs.com/Wayou/p/gmail_like_page_loading_progress_bar.html