Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么-創(chuàng)新互聯(lián)

本篇內(nèi)容介紹了“Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

站在用戶的角度思考問題,與客戶深入溝通,找到遜克網(wǎng)站設(shè)計與遜克網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名與空間、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋遜克地區(qū)。

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

不知你是否從上面這張圖中注意到了什么,比如只是渲染了可視區(qū)域的部分 DOM ,滾動過程中只是外層容器的 padding 在改變?

前一點很好理解,我們考慮到性能,不可能將一個長列表(甚至是一個無限下拉列表)的所有列表元素都進行渲染;而后一點,則是本文所介紹方案的核心之一!

不賣關(guān)子,提前告訴你該方案的要素就是兩個:

  • Intersection Observer

  • padding

說明了要素,也許你可以嘗試著開始思考,看你是否能猜到具體的實現(xiàn)方案。

方案介紹

Intersection Observer

基本概念

一直以來,檢測元素的可視狀態(tài)或者兩個元素的相對可視狀態(tài)都不是件容易事。傳統(tǒng)的各種方案不但復(fù)雜,而且性能成本很高,比如需要監(jiān)聽滾動事件,然后查詢 DOM , 獲取元素高度、位置,計算距離視窗高度等等。

這就是 Intersection Observer 要解決的問題。它為開發(fā)人員提供一種便捷的新方法來異步查詢元素相對于其他元素或視窗的位置,消除了昂貴的 DOM 查詢和樣式讀取成本。

兼容性

主要在 Safari 上兼容性較差,需要 12.2 及以上才兼容,不過還好,有 polyfill 可食用。

一些應(yīng)用場景
  • 頁面滾動時的懶加載實現(xiàn)。

  • 無限下拉(本文的實現(xiàn))。

  • 監(jiān)測某些廣告元素的曝光情況來做相關(guān)數(shù)據(jù)統(tǒng)計。

  • 監(jiān)測用戶的滾動行為是否到達了目標(biāo)位置來實現(xiàn)一些交互邏輯(比如視頻元素滾動到隱藏位置時暫停播放)。

padding 方案實現(xiàn)

基本了解 Intersection Observer 之后,接下來就看下如何用 Intersection Observer + padding 來實現(xiàn)無限下拉。

先概覽下總體思路:

  • 監(jiān)聽一個固定長度列表的首尾元素是否進入視窗;

  • 更新當(dāng)前頁面內(nèi)渲染的第一個元素對應(yīng)的序號;

  • 根據(jù)上述序號,獲取目標(biāo)數(shù)據(jù)元素,列表內(nèi)容重新渲染成對應(yīng)內(nèi)容;

  • 容器 padding 調(diào)整,模擬滾動實現(xiàn)。

核心:利用父元素的 padding 去填充隨著無限下拉而本該有的、越來越多的 DOM 元素,僅僅保留視窗區(qū)域上下一定數(shù)量的 DOM 元素來進行數(shù)據(jù)渲染。

1、監(jiān)聽一個固定長度列表的首尾元素是否進入視窗
// 觀察者創(chuàng)建
this.observer = new IntersectionObserver(callback, options);

// 觀察列表第一個以及最后一個元素
this.observer.observe(this.firstItem);
this.observer.observe(this.lastItem);

我們以在頁面中渲染固定的 20 個列表元素為例,我們對第一個元素和最后一個元素,用 Intersection Observer 進行觀察,當(dāng)他們其中一個重新進入視窗時,callback 函數(shù)就會觸發(fā):

const callback = (entries) => {
   entries.forEach((entry) => {
       if (entry.target.id === firstItemId) {
           // 當(dāng)?shù)谝粋€元素進入視窗
       } else if (entry.target.id === lastItemId) {
           // 當(dāng)最后一個元素進入視窗
       }
   });
};
2、更新當(dāng)前頁面渲染的第一個元素對應(yīng)的序號 (firstIndex)

拿具體例子來說明,我們用一個數(shù)組來維護需要渲染到頁面中的數(shù)據(jù)。數(shù)組的長度會隨著不斷請求新的數(shù)據(jù)而不斷變大,而渲染的始終是其中一定數(shù)量的元素,比如 20 個。那么:

  • 1、最開始渲染的是數(shù)組中序號為 0 - 19 的元素,即此時對應(yīng)的 firstIndex 為 0;

  • 2、當(dāng)序號為 19 的元素(即上一步的 lastItem )進入視窗時,我們就會往后渲染 10 個元素,即渲染序號為 10 - 29 的元素,那么此時的 firstIndex 為 10;

  • 3、下一次就是,當(dāng)序號為 29 的元素進入視窗時,繼續(xù)往后渲染 10個元素,即渲染序號為 20 - 39 的元素,那么此時的 firstIndex 為 20,以此類推。。。

// 我們對原先的 firstIndex 做了緩存
const { currentIndex } = this.domDataCache;

// 以全部容器內(nèi)所有元素的一半作為每一次渲染的增量
const increment = Math.floor(this.listSize / 2);

let firstIndex;

if (isScrollDown) {
   // 向下滾動時序號增加
   firstIndex = currentIndex + increment;
} else {
   // 向上滾動時序號減少
   firstIndex = currentIndex - increment;
}

總體來說,更新 firstIndex,是為了根據(jù)頁面的滾動情況,知道接下來哪些數(shù)據(jù)應(yīng)該被獲取、渲染。

3、根據(jù)上述序號,獲取對應(yīng)數(shù)據(jù)元素,列表重新渲染成新的內(nèi)容
const renderFunction = (firstIndex) => {
   // offset = firstIndex, limit = 10 => getData
   // getData Done =>  new dataItems => render DOM
};

這一部分就是根據(jù) firstIndex 查詢數(shù)據(jù),然后將目標(biāo)數(shù)據(jù)渲染到頁面上即可。

4、padding 調(diào)整,模擬滾動實現(xiàn)

既然數(shù)據(jù)的更新以及 DOM 元素的更新我們已經(jīng)實現(xiàn)了,那么無限下拉的效果以及滾動的體驗,我們要如何實現(xiàn)呢?

想象一下,拋開一切,最原始最直接最粗暴的方式無非就是我們再又獲取了 10 個新的數(shù)據(jù)元素之后,再塞 10 個新的 DOM 元素到頁面中去來渲染這些數(shù)據(jù)。

但此時,對比上面這個粗暴的方案,我們的方案是:這 10個新的數(shù)據(jù)元素,我們用原來已有的 DOM 元素去渲染,替換掉已經(jīng)離開視窗、不可見的數(shù)據(jù)元素;而本該有更多 DOM 元素進一步撐開容器高度的部分,我們用 padding 填充來模擬實現(xiàn)。

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

  • 向下滾動

// padding的增量 = 每一個item的高度 x 新的數(shù)據(jù)項的數(shù)目
const remPaddingsVal = itemHeight * (Math.floor(this.listSize / 2));

if (isScrollDown) {
   // paddingTop新增,填充頂部位置
   newCurrentPaddingTop = currentPaddingTop + remPaddingsVal;

   if (currentPaddingBottom === 0) {
       newCurrentPaddingBottom = 0;
   } else {
       // 如果原來有paddingBottom則減去,會有滾動到底部的元素進行替代
       newCurrentPaddingBottom = currentPaddingBottom - remPaddingsVal;
   }
}

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

  • 向上滾動

// padding的增量 = 每一個item的高度 x 新的數(shù)據(jù)項的數(shù)目
const remPaddingsVal = itemHeight * (Math.floor(this.listSize / 2));

if (!isScrollDown) {
   // paddingBottom新增,填充底部位置
   newCurrentPaddingBottom = currentPaddingBottom + remPaddingsVal;

   if (currentPaddingTop === 0) {
       newCurrentPaddingTop = 0;
   } else {
       // 如果原來有paddingTop則減去,會有滾動到頂部的元素進行替代
       newCurrentPaddingTop = currentPaddingTop - remPaddingsVal;
   }
}

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么

  • 最后是 padding 設(shè)置更新以及相關(guān)緩存數(shù)據(jù)更新

// 容器padding重新設(shè)置
this.updateContainerPadding({
   newCurrentPaddingBottom,
   newCurrentPaddingTop
})

// DOM元素相關(guān)數(shù)據(jù)緩存更新
this.updateDomDataCache({
   currentPaddingTop: newCurrentPaddingTop,
   currentPaddingBottom: newCurrentPaddingBottom
});

思考總結(jié)

方案總結(jié):

利用 Intersection Observer 來監(jiān)測相關(guān)元素的滾動位置,異步監(jiān)聽,盡可能得減少 DOM 操作,觸發(fā)回調(diào),然后去獲取新的數(shù)據(jù)來更新頁面元素,并且用調(diào)整容器 padding 來替代了本該越來越多的 DOM 元素,最終實現(xiàn)列表滾動、無限下拉。

相關(guān)方案的對比

這里和較為有名的庫 - iScroll 實現(xiàn)的無限下拉方案進行一個基本的對比,對比之前先說明下 iScroll infinite 的實現(xiàn)概要:

  • iScroll 通過對傳統(tǒng)滾動事件的監(jiān)聽,獲取滾動距離,然后:

  • 設(shè)置父元素的 translate 來實現(xiàn)整體內(nèi)容的上移(下移);

  • 再基于這個滾動距離進行相應(yīng)計算,得知相應(yīng)子元素已經(jīng)被滾動到視窗外,并且判斷是否應(yīng)該將這些離開視窗的子元素移動到末尾,從而再對它們進行 translate 的設(shè)置來移動到末尾。這就像是一個循環(huán)隊列一樣,隨著滾動的進行,頂部元素先出視窗,但又將移動到末尾,從而實現(xiàn)無限下拉。

  • 相關(guān)對比:

    • 實現(xiàn)對比:一個是 Intersection Observer 的監(jiān)聽,來通知子元素離開視窗,只要定量設(shè)置父元素 padding 就行;另一個是對傳統(tǒng)滾動事件的監(jiān)聽,滾動距離的獲取,再進行一系列計算,去設(shè)置父元素以及子元素的 translate。顯而易見,前者看起來更加簡潔明了一些。

    • 性能對比:我知道說到對比,你腦海中肯定一下子會想到性能問題。其實性能對比的關(guān)鍵就是 Intersection Observer。因為單就 padding 設(shè)置還是 translate 設(shè)置,性能方面的差距是甚小的,只是個人感覺 padding 會簡潔些?而 Intersection Observer 其實抽離了所有滾動層面的相關(guān)邏輯,你不再需要對滾動距離等相應(yīng) DOM 屬性進行獲取,也不再需要進行一系列滾動距離相關(guān)的復(fù)雜計算,并且同步的滾動事件觸發(fā)變成異步的,你也不再需要另外去做防抖之類的邏輯,這在性能方面還是有所提升的。

存在的缺陷:
  • padding 的計算依賴列表項固定的高度。

  • 這是一個同步渲染的方案,也就是目前容器 padding 的計算調(diào)整,無法計算異步獲取的數(shù)據(jù),只跟用戶的滾動行為有關(guān)。這看起來與實際業(yè)務(wù)場景有些不符。解決思路:

    • 思路 1、利用 Skeleton Screen Loading 來同步渲染數(shù)據(jù)元素,不受數(shù)據(jù)異步獲取的影響。即在數(shù)據(jù)請求還未完成時,先使用一些圖片進行占位,待內(nèi)容加載完成之后再進行替換。

    • 思路 2、滾動到目標(biāo)位置,阻塞容器 padding 的設(shè)置(即無限下拉的發(fā)生)直至數(shù)據(jù)請求完畢,用 loading gif 提示用戶加載狀態(tài),但這個方案相對復(fù)雜,你需要全面考慮用戶難以預(yù)測的滾動行為來設(shè)置容器的 padding。

“Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

新聞標(biāo)題:Python簡潔且有趣的無限下拉的實現(xiàn)方法是什么-創(chuàng)新互聯(lián)
路徑分享:http://muchs.cn/article18/dppgdp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護服務(wù)器托管、面包屑導(dǎo)航云服務(wù)器、微信公眾號、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)