1. 程式人生 > >sui mobile 無限滾動時會觸發多次請求問題

sui mobile 無限滾動時會觸發多次請求問題

首先,說問題之前,首先我們先看一下sui mobile 官網無限滾動的實現程式碼,(這裡主要是說底部無限滾動)。 
官網中提到,要實現無限滾動,只需要“在可滾動的容器上新增“infinite-scroll”類,一般是頁面滾動區域 - div.content”

這裡寫圖片描述

其中,data-distance - 屬性用來配置頁面滾動到離底部多遠時觸發無限滾動事件,預設是50 (px)。另外,以下,是官網demo中實現無限滾動的js部分。

這裡寫圖片描述

官網的demo中可以看出,它實現此功能並沒有涉及到任何的請求,對於我們真正要在專案中實現此功能時,如果是單單把返回的資料展現出來,或許還適用,但是,往往我們在專案中都會涉及到請求及分頁顯示資料,此時由於涉及到了請求資料操作,如果再像demo中的方法去實現,就有可能發生了頻繁傳送請求的問題了,而通常,我們的需求確是當我們手滑動螢幕,當底部出現載入時才開始發出請求。此時,我們需對js進行如下修改。

這裡寫圖片描述

以上程式碼就是涉及到資料請求的處理,只是,如果資料請求是非同步請求,那麼上面的實現方法還是存在問題的。首先看,圖中的紅框的第一步,重置loading,第二個紅框,資料請求。如果使用者每次都只是滑動一次,正常來說是沒問題,但是,假如使用者不斷地上下滑動,那麼,當滾動條距離底部data-distance 的畫素時,就會觸發請求,如果多次觸發請求,那麼由於是非同步請求,它的上一個請求可能還沒完成,而loading就被重置了,這樣也會導致卡頓或者其他問題。因此,我們可以再次進行修改,把重置loading這個修改標示放到非同步請求完成之後的回撥函式裡面,同理,.infinite-scroll-preloader提示層新增loadHide樣式也一樣要放到請求完成後的回撥函式裡面。程式碼如下:

這裡寫圖片描述

經過以上的修改,就實現了非同步請求資料操作功能了,開心的,以為這一模組終於可以告一段落了。然而(納尼,還有但書?不要嚇寶寶啊,寶寶的小心臟,嚶嚶嚶),某天同組小夥伴console測試,發現,別說是快速上下滑動螢幕了,就是小心翼翼地滑動一次,測試結果,console語句至少都會執行兩次。小夥伴把問題描述後,本寶就再次加深研究,終於是找出了原因了。 
sui mobile實現無限滾動,在DOM結構中必須有的屬性為data-distance,而且這個值不能為0,為0的話不管如何滾動都不會觸發infinite事件,進而不會有任何請求發生。此時,假設data-distance的屬性值為30,只要滾動條距離底部30畫素的區域範圍內有任何的滾動,不管是向下滾動還是向上滾動,都會觸發infinite事件。知道原理後,那麼原因就很簡單了。當用戶向下滑動滾動條時,滾動條底端距離底部小於等於30px時,觸發一次infinite事件,而此時,在達到這個條件時,底部會顯示一個“正在載入”的提示語,DOM結構內容新增,那麼滾動條可能在30px範圍內滑動,此時又觸發infinite事件,這是“至少會執行兩次”的原因,如果執行多次,那麼有可能就是首次觸發infinite事件時,發生請求,返回新條目後DOM結構又新新增新內容,滾動條又滑動,若還在30px範圍內就會再次觸發……,如此一來,才會存在有觸發多次,甚至發起多次請求的問題。 
那麼又該如何處理才能避免多次觸發併發起請求這個問題呢?相信很多童鞋們,看到滾動、避免多次呼叫,會想到debounce和throttle 函式,關於debounce和throttle的區別這裡不多加解釋,有興趣的娃可以自行查閱相關資料去了解。我這裡主要是用到undercore裡面的_.debounce函式來處理的,並且對滾動條滾動的方向進行判斷一下,當滾動條向下滑動時才觸發併發起請求,向上滑動時不發起請求。此外,應該注意的是在請求出錯是,當前頁數應要再減1,因為當前頁數在發起請求前就加1了,所以出錯時要回到上一個請求的頁碼(此細節未在下圖程式碼中體現)。具體程式碼如下所示:

這裡寫圖片描述

以上才終於算是對無限滾動觸發多次請求問題進行了較符合需求的處理,可能還會存在問題,如發現有什麼問題,歡迎留言,共同探討。