国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[源碼閱讀]通過react-infinite-scroller理解滾動(dòng)加載要點(diǎn)

cikenerd / 3054人閱讀

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

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

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

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

參數(shù):

// 渲染出來的DOM元素name
element: "div",
// 是否能繼續(xù)滾動(dòng)渲染
hasMore: false,
// 是否在訂閱事件的時(shí)候執(zhí)行事件
initialLoad: true,
// 表示當(dāng)前翻頁的值(每渲染一次遞增)
pageStart: 0,
// 傳遞ref,返回此組件渲染的 DOM
ref: null,
// 觸發(fā)渲染的距離
threshold: 250,
// 是否在window上綁定和處理距離
useWindow: true,
// 是否反向滾動(dòng),即到頂端后渲染
isReverse: false,
// 是否使用捕獲模式
useCapture: false,
// 渲染前的loading組件
loader: null,
// 自定義滾動(dòng)組件的父元素
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個(gè)事件,分別是scroll,resize,mousewheel

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

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

mousewheel解決chrome的等待bug

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

stackoverflow:Chrome的滾動(dòng)等待問題

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

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

以上綁定可以消除這個(gè)"bug"。

個(gè)人并沒有遇到過這種情況,不知道是否有遇到過可以說說解決方案。
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指 滾動(dòng)到頂端,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)該要判斷確保滾動(dò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));
    }
  }
}

組件核心。

幾個(gè)學(xué)習(xí)/復(fù)習(xí)點(diǎn)

offsetParent

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

offsetParent很有用,因?yàn)橛?jì)算offsetTopoffsetLeft都是相對(duì)于offsetParent邊界的。

ele.offsetParent為 null 的3種情況:

ele 為body

ele 的positionfixed

ele 的displaynone

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

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

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

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

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

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

scrollHeightclientHeight

在無滾動(dòng)的情況下,scrollHeightclientHeight相等,都為height+padding*2

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

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

確保不會(huì)重復(fù)(過多)執(zhí)行loadMore,因?yàn)橄刃遁d事件再執(zhí)行loadMore,可以確保在執(zhí)行過程中,scroll事件是無效的,然后再每次componentDidUpdate的時(shí)候重新綁定事件。

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;

  // 定義一個(gè)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);
}

這里一個(gè)小亮點(diǎn)就是,在react中,this.props是不允許修改的。

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

getScrollParent,
...props
} = renderProps;

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

總結(jié)

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

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

Chrome的一個(gè)滾動(dòng)加載請(qǐng)求的bug。本文位置

offsetParent的一些實(shí)際用法。本文位置

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

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

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

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

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

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99394.html

相關(guān)文章

  • 給Ant Design list列表增加滑動(dòng)框功能

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

    ISherry 評(píng)論0 收藏0
  • 深入理解js

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

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

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

    elarity 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<