現在類似於pinterest這類的表現效果很火,其實我比較中意的是他的布局效果,而不是那種瀑布流。
雖然我不是特別喜歡這種瀑布流的表現樣式,但是還是寫了幾篇關於無限滾動瀑布流效果的文章,Infinite scroll+Masonry=無限滾動瀑布流,infinite-scroll-jquery滾動條(下拉)加載數據插件之類的文章。可能是我表達描述不是很詳細清楚,所以好多朋友看了不是很清楚,並發信給我求解釋。所以有了今天這篇文章。
其實早在:十幾款jquery無限滾動插件這篇文章中我就提到過這種效果的實現原理。主要是判斷滾動條滾動的位置距離底部的距離,如果小於或者等於設置的高度的話,那么就執行ajax加載異步數據到固定的盒子中。我想大家對於這點是比較清楚的,恐怕對於怎樣獲取數據有點不甚了了的感覺。OK,下面看痞子的步步解析!
無限滾動第一步,ajax異步加載的條件:
我們都知道,對於一些列表頁面的布局結構都是一樣的,數據部分是由程序生成的。並且每個頁面都有下一頁的鏈接地址。OK完畢,這點這是基本條件(注意紅色部分)。
為了給大家做直觀的對比,我這里拿出3個頁面進行對比分析,其中采用的masonry的效果,關於這個插件我這里不多說,可以看Masonry-jquery插件打造的瀑布流樣式效果來對該效果有個簡單的認識。這三個頁面的結構是一樣的,內容是不一樣的(我們用不同的圖片來區分)。
這三個頁面左邊都有下一頁的鏈接,鏈接層次分別是
default.html -> default1.html ->default2.html -> 無
下面是三個頁面地址:
http://www.niumowang.org/demo/infinite/default.html
http://www.niumowang.org/demo/infinite/default1.html
http://www.niumowang.org/demo/infinite/default2.html
我們點擊每個頁面的下一頁會看到,頁面會打開一個新的頁面結構與之前的頁面相同,內容不同。最后一個頁面default2.html的下一頁鏈接處是空連接,代表后面沒有頁面了。
無限滾動第二步,ajax異步加載如何進行:
第一步的工作完成后,我們要在上面的下一頁鏈接處做文章。在第一步提供的鏈接中,我們點擊下一頁都會打開下一頁的鏈接,並顯示內容。但是我們現在要做的就是用ajax異步加載數據到當前頁面,實現點擊鏈接不打開新的頁面,但是加載這個鏈接中的數據到本頁面。這里當然就用到了ajax了,所幸jquery封裝的ajax比較簡單,我們很容易實現將其他頁面的內容加載到當前頁面中。
還是三個結構相同,內容不同的頁面:(點擊下一頁可以看到效果)
http://www.niumowang.org/demo/infinite/ajax.html
http://www.niumowang.org/demo/infinite/ajax1.html
http://www.niumowang.org/demo/infinite/ajax2.html
我們來看具體實現代碼部分
$(".next_page a").click(function() { //首先取得下一頁的鏈接地址 var href = $(this).attr("href"); //判斷該鏈接是否被加載過 startHref = href; //判斷下一頁的鏈接地址是否存在 if (href != undefined) { //如果存在的話,用ajax獲取數據 $.ajax({ type: "get", url: href, success: function(data) { //將返回的數據進行處理,挑選出class是post的內容塊 var $res = $(data).find(".post"); //結合masonry插件,將內容append進ID是content的內容塊中 $("#content").append($res).masonry('appended', $res); //newHref獲取返回的內容中的下一頁的鏈接地址 var newHref = $(data).find(".next_page a").attr("href"); //判斷下一頁地址是否存在,如果存在,替換當前頁的鏈接地址。不存在,將當前頁鏈接地址屬性href移除,並替換內容為“下一頁沒有了” if (newHref != undefined) { $(".next_page a").attr("href", newHref); } else { $(".next_page a").html("下一頁沒有了").removeAttr("href") } } }) } //返回false,使得點擊進入新頁面失效 return false; })
用文字表達一下這個過程就是:點擊鏈接,異步加載這個鏈接中的數據后,挑選出符合條件的內容,然后將內容用js加載到這個頁面固定的容器中,並且將這個鏈接的地址替換成新的鏈接地址。並對如果沒有下一頁的情況進行處理。
其中找到下一頁的鏈接地址可能情況比較多變一些,比如存在“123456…”這樣的鏈接結構;當然這種情況的話,我們可以采用獲取比如class為current的鏈接地址,那么下一頁的地址就是current后面的一個鏈接,然后用返回數據將包含所有分頁地址的容器替換掉。所謂具體問題具體分析,這里點到即止。
另外就是masonry將ajax返回的數據進行重新布局的操作了,這個屬於masonry的范疇,不做過多解釋。關於masonry自己從本站找相關資料。
無限滾動第三步,滾動條控制無限加載:
所謂滾動條控制無限滾動,只不過把點擊的效果替換掉。我們通過滾動鼠標滾輪,或者拖動滾動條到底部來實現原來的點擊異步加載數據的情況。
如果你要實現的話,該怎么做呢?
是的,我們只需要判斷滾動條距離底部的位置就行了。如果到了底部,我們就加載一次數據。
但是還有一個問題,由於我們需要實時獲取滾動條的最新位置,而獲取滾動條位置不是自動的,我們總不能點擊一個按鈕獲取一次數據吧,或者用setTimeout,每隔一段時間獲取一次數據。當然這些都是不可行的。
比較可行的方法就是:我們給(window)窗口綁定一個scroll事件,所謂綁定事件就是監聽這個對象,監視它的一舉一動。如果window窗口滾動的時候,滾動條到底了,那么我們可以進行我們的小動作異步加載數據進來了。OK,看代碼實現。
//首先給窗口綁定事件scroll $(window).bind("scroll",function() { // 然后判斷窗口的滾動條是否接近頁面底部,這里的20可以自定義 if ($(document).scrollTop() + $(window).height() > $(document).height() - 20) { //我這里偷個懶,沒有寫ajax的調用,直接觸發了鏈接的click事件。 if($(".next_page a").attr('href') != startHref){ //這里判斷當前要加載的鏈接是否已經加載過 $(".next_page a").trigger("click"); } } })
演示地址:http://www.niumowang.org/demo/infinite/auto_ajax.html
上面代碼部分,我沒有寫ajax的具體調用過程,而是在原基礎上觸發了鏈接的點擊事件。如果想要看滾動實現的ajax效果的,打開地址:http://www.niumowang.org/demo/infinite/auto_ajax1.html自行查看代碼部分。
上面有個數字是20,就是滾動條距離底部還是20像素的時候開始加載。這里是為了實現預先加載效果,不至於當用戶滾動到底部的時候,數據還沒有加載出來,如果你感覺你的內容較大的話,還可以增加這個值。
無限滾動效果實現原理,總結:
至此一個滾動條實現無限滾動的效果就說完了。做一個最后的總結工作。
可以說目前網上實現無限滾動的效果各有千秋,基於的框架也不盡相同。我寫這篇文章的目的是讓大家領會一種思路,能明白這種效果是怎么做出來的。
我這種方法的文字原理部分:滾動條滾動后,如果到達底部,或者距離底部一段距離的時候,找到下一頁的鏈接地址,獲取這個地址中的數據。然后將返回的數據,采用重新布局添加到固定的容器中。OK,就這么簡單。
無限滾動的高級進階部分:
話說高級進階也沒有多么高級,只不過可能加載數據不是采用這種get或者post,哪怕load頁面的方式,而是通過傳參,從數據庫讀取數據。亦或是增加一些返回數據的特效,比如返回數據后,重新布局的時候增加點動畫,或者滾動條增加點平滑滾動效果。不過爾爾,記住一句話:只要去實踐,一切技術派都是紙老虎。
2013.06.01 BUG調整
下面好幾個朋友提到了多次加載的問題,由於當初設計的時候沒有考慮到加載內容后滾動條變化的問題。所以出現了這個情況。近日有時間解決一下。順便感謝下面提出問題的幾位朋友。
修改方法,主要是定義一個全局變量 var startHref ;
然后next_page觸發一次之后,修改此startHref的值,在滾動的時候拿到當前的next_page中鏈接的值,與startHref進行對比,如果不同的話再執行加載過程。
效果查看:http://www.niumowang.org/demo/infinite/auto_ajax.html