成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[源碼閱讀]通過react-infinite-scroller理解滾動加載要點

cikenerd / 3071人閱讀

摘要:看它的源碼主要意義不在知道如何使用它,而是知道以后處理滾動加載要注意的東西。通過判斷不為的情況,確保滾動組件正常顯示和在無滾動的情況下,和相等,都為在有滾動的情況下,表示實際內(nèi)容高度,表示視口高度。

react-infinite-scroller就是一個組件,主要邏輯就是addEventListener綁定scroll事件。

看它的源碼主要意義不在知道如何使用它,而是知道以后處理滾動加載要注意的東西。

此處跳到總結(jié)。
初識

參數(shù):

// 渲染出來的DOM元素name
element: "div",
// 是否能繼續(xù)滾動渲染
hasMore: false,
// 是否在訂閱事件的時候執(zhí)行事件
initialLoad: true,
// 表示當(dāng)前翻頁的值(每渲染一次遞增)
pageStart: 0,
// 傳遞ref,返回此組件渲染的 DOM
ref: null,
// 觸發(fā)渲染的距離
threshold: 250,
// 是否在window上綁定和處理距離
useWindow: true,
// 是否反向滾動,即到頂端后渲染
isReverse: false,
// 是否使用捕獲模式
useCapture: false,
// 渲染前的loading組件
loader: null,
// 自定義滾動組件的父元素
getScrollParent: null,
深入 componentDidMount
componentDidMount() {
  this.pageLoaded = this.props.pageStart;
  this.attachScrollListener();
}

執(zhí)行attachScrollListener

attachScrollListener
attachScrollListener() {
  const parentElement = this.getParentElement(this.scrollComponent);
  
  if (!this.props.hasMore || !parentElement) {
    return;
  }

  let scrollEl = window;
  if (this.props.useWindow === false) {
    scrollEl = parentElement;
  }
  scrollEl.addEventListener(
    "mousewheel",
    this.mousewheelListener,
    this.props.useCapture,
  );
  scrollEl.addEventListener(
    "scroll",
    this.scrollListener,
    this.props.useCapture,
  );
  scrollEl.addEventListener(
    "resize",
    this.scrollListener,
    this.props.useCapture,
  );
  
  if (this.props.initialLoad) {
    this.scrollListener();
  }
}

此處通過getParentElement獲取父組件(用戶自定義父組件或者當(dāng)前dom的parentNode)

然后綁定了3個事件,分別是scroll,resize,mousewheel

前2種都綁定scrollListener,mousewheel是一個非標(biāo)準(zhǔn)事件,是不建議在生產(chǎn)模式中使用的。

那么這里為什么要使用呢?

mousewheel解決chrome的等待bug

此處的mousewheel事件是為了處理chrome瀏覽器的一個特性(不知道是否是一種bug)。

stackoverflow:Chrome的滾動等待問題

上面這個問題主要描述,當(dāng)在使用滾輪加載,而且加載會觸發(fā)ajax請求的時候,當(dāng)滾輪到達(dá)底部,會出現(xiàn)一個漫長而且無任何動作的等待(長達(dá)2-3s)。

window.addEventListener("mousewheel", (e) => {
    if (e.deltaY === 1) {
        e.preventDefault()
    }
})

以上綁定可以消除這個"bug"。

個人并沒有遇到過這種情況,不知道是否有遇到過可以說說解決方案。
getParentElement
getParentElement(el) {
  const scrollParent =
    this.props.getScrollParent && this.props.getScrollParent();
  if (scrollParent != null) {
    return scrollParent;
  }
  return el && el.parentNode;
}

上面用到了getParentElement,很好理解,使用用戶自定義的父組件,或者當(dāng)前組件DOM.parentNode

scrollListener
scrollListener() {
  const el = this.scrollComponent;
  const scrollEl = window;
  const parentNode = this.getParentElement(el);

  let offset;
  // 使用window的情況
  if (this.props.useWindow) {
    const doc = document.documentElement || document.body.parentNode || document.body;
    const scrollTop = scrollEl.pageYOffset !== undefined
        ? scrollEl.pageYOffset
        : doc.scrollTop;
    // isReverse指 滾動到頂端,load新組件
    if (this.props.isReverse) {
      // 相反模式獲取到頂端距離
      offset = scrollTop;
    } else {
      // 正常模式則獲取到底端距離
      offset = this.calculateOffset(el, scrollTop);
    }
    // 不使用window的情況
  } else if (this.props.isReverse) {
    // 相反模式組件到頂端的距離
    offset = parentNode.scrollTop;
  } else {
    // 正常模式組件到底端的距離
    offset = el.scrollHeight - parentNode.scrollTop - parentNode.clientHeight;
  }

  // 此處應(yīng)該要判斷確保滾動組件正常顯示
  if (
    offset < Number(this.props.threshold) &&
    (el && el.offsetParent !== null)
  ) {
    // 卸載事件
    this.detachScrollListener();
    // 卸載事件后再執(zhí)行 loadMore
    if (typeof this.props.loadMore === "function") {
      this.props.loadMore((this.pageLoaded += 1));
    }
  }
}

組件核心。

幾個學(xué)習(xí)/復(fù)習(xí)點

offsetParent

offsetParent返回一個指向最近的包含該元素的定位元素.

offsetParent很有用,因為計算offsetTopoffsetLeft都是相對于offsetParent邊界的。

ele.offsetParent為 null 的3種情況:

ele 為body

ele 的positionfixed

ele 的displaynone

此組件中offsetParent處理了2種情況

useWindow的情況下(即事件綁定在window,滾動作用在body)

通過遞歸獲取offsetParent到達(dá)頂端的高度(offsetTop)。

calculateTopPosition(el) {
 if (!el) {
   return 0;   
 }
 return el.offsetTop + this.calculateTopPosition(el.offsetParent);   
}

通過判斷offsetParent不為null的情況,確保滾動組件正常顯示

  if (
    offset < Number(this.props.threshold) &&
    (el && el.offsetParent !== null)
  ) {/* ... */ }

scrollHeightclientHeight

在無滾動的情況下,scrollHeightclientHeight相等,都為height+padding*2

在有滾動的情況下,scrollHeight表示實際內(nèi)容高度,clientHeight表示視口高度。

每次執(zhí)行loadMore前卸載事件。

確保不會重復(fù)(過多)執(zhí)行loadMore,因為先卸載事件再執(zhí)行loadMore,可以確保在執(zhí)行過程中,scroll事件是無效的,然后再每次componentDidUpdate的時候重新綁定事件。

render
render() {
  // 獲取porps
  const renderProps = this.filterProps(this.props);
  const {
    children,
    element,
    hasMore,
    initialLoad,
    isReverse,
    loader,
    loadMore,
    pageStart,
    ref,
    threshold,
    useCapture,
    useWindow,
    getScrollParent,
    ...props
  } = renderProps;

  // 定義一個ref
  // 能將當(dāng)前組件的DOM傳出去
  props.ref = node => {
    this.scrollComponent = node;
    // 執(zhí)行父組件傳來的ref(如果有)
    if (ref) {
      ref(node);
    }
  };

  const childrenArray = [children];
  // 執(zhí)行l(wèi)oader
  if (hasMore) {
    if (loader) {
      isReverse ? childrenArray.unshift(loader) : childrenArray.push(loader);
    } else if (this.defaultLoader) {
      isReverse
        ? childrenArray.unshift(this.defaultLoader)
        : childrenArray.push(this.defaultLoader);
    }
  }
  // ref 傳遞給 "div"元素
  return React.createElement(element, props, childrenArray);
}

這里一個小亮點就是,在react中,this.props是不允許修改的。

這里使用了解構(gòu)

getScrollParent,
...props
} = renderProps;

這里解構(gòu)相當(dāng)于Object.assign,定義了一個新的object,便可以添加屬性了,并且this.props不會受到影響。

總結(jié)

react-infinite-scroller邏輯比較簡單。

一些注意/學(xué)習(xí)/復(fù)習(xí)點:

Chrome的一個滾動加載請求的bug。本文位置

offsetParent的一些實際用法。本文位置

通過不斷訂閱和取消事件綁定讓滾動執(zhí)行函數(shù)不會頻繁觸發(fā)。本文位置

scrollHeightclientHeight區(qū)別。本文位置

此庫建議使用在自定義的一些組件上并且不那么復(fù)雜的邏輯上。

用在第三方庫可以會無法獲取正確的父組件,而通過document.getElementBy..傳入。

面對稍微復(fù)雜的邏輯,

例如,一個搜索組件,訂閱onChange事件并且呈現(xiàn)內(nèi)容,搜索"a",對呈現(xiàn)內(nèi)容滾動加載了3次,再添加搜索詞"b",這時候"ab"的內(nèi)容呈現(xiàn)是在3次之后。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/99394.html

相關(guān)文章

  • 給Ant Design list列表增加滑動框功能

    摘要:描述最近在用框架寫一個項目遇到了一個小問題列表會加載出很多數(shù)據(jù)需要在固定區(qū)域查看所有的列表數(shù)據(jù)需求給列表增加一個滑動框開始在官網(wǎng)上看了下例子比較復(fù)雜是結(jié)合實現(xiàn)滾動自動加載列表。 描述:最近在用Ant Design 框架寫一個項目,遇到了一個小問題,list列表會加載出很多數(shù)據(jù).需要在固定區(qū)域查看所有的列表數(shù)據(jù).需求:給list列表增加一個滑動框 開始在官網(wǎng)上看了下例子.比較復(fù)雜..是l...

    ISherry 評論0 收藏0
  • 深入理解js

    摘要:詳解十大常用設(shè)計模式力薦深度好文深入理解大設(shè)計模式收集各種疑難雜癥的問題集錦關(guān)于,工作和學(xué)習(xí)過程中遇到過許多問題,也解答過許多別人的問題。介紹了的內(nèi)存管理。 延遲加載 (Lazyload) 三種實現(xiàn)方式 延遲加載也稱為惰性加載,即在長網(wǎng)頁中延遲加載圖像。用戶滾動到它們之前,視口外的圖像不會加載。本文詳細(xì)介紹了三種延遲加載的實現(xiàn)方式。 詳解 Javascript十大常用設(shè)計模式 力薦~ ...

    caikeal 評論0 收藏0
  • Vue下滾動到頁面底部無限加載數(shù)據(jù)Demo

    摘要:下滾動到頁面底部無限加載數(shù)據(jù)看到一篇覺得挺實用的就看了下順便簡單翻譯了一下給需要的人參考從這個項目中可以加深對的生命周期的理解何時開始請求如何結(jié)合使用原生來寫事件等等我這里主要是對原文的重點提取和補(bǔ)充本文技術(shù)要點生命周期簡單用法格式化日期圖 Vue下滾動到頁面底部無限加載數(shù)據(jù)Demo 看到一篇Implementing an Infinite Scroll with Vue.js, 覺得...

    elarity 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<