Vant-list源碼詳解

一、源碼理解基礎之scroll.js

1、1 >>> getScrollEventTarget

export default {
getScrollEventTarget(element, rootParent = window) {
    let currentNode = element;
    while (currentNode && currentNode.tagName !== 'HTML' && currentNode.tagName !== 'BODY' && currentNode.nodeType === 1 && currentNode !== rootParent) {
      const overflowY = this.getComputedStyle(currentNode).overflowY;
      if (overflowY === 'scroll' || overflowY === 'auto') {
        return currentNode;
      }
      currentNode = currentNode.parentNode;
    }
    return rootParent;
  }
}

getScrollEventTarget:

這個函數用於找到“目標容器”,即:有滾動條的dom。

 

1、2>>>  getScrollTop

 getScrollTop(element) {
    return 'scrollTop' in element ? element.scrollTop : element.pageYOffset;
  }

getScrollTop:

獲取元素的滾動條高度。

Element.scrollTop 屬性可以獲取或設置一個元素的內容垂直滾動的像素數。

一個元素的 scrollTop 值是這個元素的頂部到它的最頂部可見內容(的頂部)的距離的度量。當一個元素的內容沒有產生垂直方向的滾動條,那麼它的 scrollTop 值爲0。

 

1、3>>> getElementTop

 getElementTop(element) {
    return (element === window ? 0 : element.getBoundingClientRect().top) + this.getScrollTop(window);
  },

getElementTop:

元素頂部至頁面頂部的距離

getBoundingClientRect用於獲得頁面中某個元素的左,上,右和下分別相對瀏覽器視窗的位置。

 

1、4>>>  getVisibleHeight

  getVisibleHeight(element) {
    return element === window ? element.innerHeight : element.getBoundingClientRect().height;
  },

getVisibleHeight:

獲取元素高度

 

二、源碼理解之index.vue

重要源碼部分

  methods: {
    check() {
      if (this.loading || this.finished) {
        return;
      }

      const el = this.$el;
      const { scroller } = this;
      // scrollerHeight 容器可見高度
      const scrollerHeight = utils.getVisibleHeight(scroller);

      /* istanbul ignore next */
      if (!scrollerHeight || utils.getComputedStyle(el).display === 'none' || el.offsetParent === null) {
        return;
      }
      // scrollTop滾動高度
      const scrollTop = utils.getScrollTop(scroller);
      const targetBottom = scrollTop + scrollerHeight;
      let reachBottom = false;
      /* istanbul ignore next */
      if (el === scroller) {
        reachBottom = scroller.scrollHeight - targetBottom < this.offset;
      } else {
        const elBottom =
          utils.getElementTop(el) -
          utils.getElementTop(scroller) +
          utils.getVisibleHeight(el);
        reachBottom = elBottom - scrollerHeight < this.offset;
      }

      /* istanbul ignore else */
      if (reachBottom) {
        this.$emit('input', true);
        this.$emit('load');
      }
    },

    handler(bind) {
      /* istanbul ignore else */
      if (this.binded !== bind) {
        this.binded = bind;
        (bind ? on : off)(this.scroller, 'scroll', this.check);
      }
    }
  }

最主要的方法是check()

重中之重是這段代碼:

const elBottom =
          utils.getElementTop(el) -
          utils.getElementTop(scroller) +
          utils.getVisibleHeight(el);
        reachBottom = elBottom - scrollerHeight < this.offset;

下面我就來解釋下這段代碼的意思:

 看圖一:

圖一
圖一

 這裏用a來表示utils.getElementTop(el)    a=152   代表dom頂部距離page頂部的距離

b表示utils.getVisibleHeight(el)  b=800   代表dom的高度

d表示utils.getElementTop(scroller) 即滾動條的滾動的高度,此時沒有滾動,即d=0

c表示scrollerHeight  即整個容器的高度

this.offset可以自定義設定

再來看圖二:

圖二

 

此時滾動條向下滾動了50

所以現在來看下

a=152

b=800

c=852

d=50

此時有變化的是utils.getElementTop(scroller)

如果我們設定this.offset=10

 reachBottom = elBottom - scrollerHeight < this.offset

                      =a-d+b-c=152-50+800-852=50 < 10

所以 reachBottom=false

所以 reachBottom還未達到觸發滾動至底部加載新內容的條件

 

如果我們設定this.offset=55

reachBottom = 50 < 55 = true

所以此時可以觸發加載新內容。

 

具體代碼可以查看https://github.com/youzan/vant/tree/dev/packages/listhttps://github.com/youzan/vant/tree/dev/packages/utils

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章