【UI库】上拉加载更多组件

需求

当滑动到底部的时候,通知父组件可以加载更多。

原理

在这里插入图片描述

scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值;
clientHeight:它是一个定值,表示屏幕可是区域的高度;
scrollHeight:页面不能滚动时是不存在的,body长度超过window时才会出现,所表示body所有元素的长度,

由上面的三个值所产生一个原理公式:

scrollTop + clientHeight >= scrollHeight

这会就是滚动到了底部了。

实现

布局

<template>
  <div class="list" ref="feed">
    <slot></slot>
    <div class="list__bottom">{
    
    {
    
    statusText}}</div>
  </div>
</template>

获得当前的滚动元素,并绑定srcoll事件

mounted(){
    
    
    this.scrollEl = getScroller(this.$el as HTMLElement);
    on(this.scrollEl, 'scroll', this.handleScroll);
    this.$once('hook:beforeDestory', () => {
    
    
      off(this.scrollEl, 'scroll', this.handleScroll);
    })
}

实现滚动监听

获得srcollTopclientHeightscrollerHeight,计算他们的差值,判断是否触底;当触底的时候即调用父组件的加载更多函数,此时isLoadMoretrue,不可以再加载,只有false才可以更多。当父组件告诉你已经不能加载更多isFinished=true时也不可以再加载更多。

private handleScroll(){
    
    
    if(this.isLoadMore || this.isFinished) return;
    
    // 滚动条距离顶部的距离
    const srcollTop = getScrollTop(this.scrollEl);
    // 可视区域高度
    const clientHeight = getVisibleHeight(this.scrollEl);
    // 内容的总高度
    const scrollerHeight = getVisibleHeight(this.placeholder);

    if(srcollTop + clientHeight >= scrollerHeight - (+this.offset)) {
    
    
      this.$emit('loadMore');
    }
}

更新底部的加载提示

get statusText(){
    
    
    if(this.isFinished) return this.finishedText;
    else if(this.isLoadMore) return this.loadingText; 
    return ''
 }

修改触底的判断逻辑

我以为按照上面的逻辑就OK了,然而我进行测试之后发现了这个逻辑的不合理性。当你在一个页面中这么使用加载更多组件是:

<template>
  <div class="wrapper">
    <div class="tmp"></div>
    <ar-list :isLoadMore="isLoadMore" :isFinished="isFinished" @loadMore="initData">
        <ul>
          <li class="list-item" v-for="(item, index) in list" :key="index">{
    
    {
    
    item}}</li>
        </ul>
     </ar-list>
  </div>
</template>

tmp是一个有200px高度的div,此时获得的scrollTop包含了200px,同理,当加载更多组件上方含有占有一定高度的元素时,必然会影响到scrllTop的取值,于是我们需要换一个思路。

先分别获得容器和插槽的getBoundingClientRect,然后计算他们的bottom差是否小于offset值,如果是则触底。这里是依据两个底部值来做计算的。

先在插槽外部包裹一个ref=placeholderdiv

<template>
  <div class="ar-list" ref="feed">
    <div class="slot-wrapper" ref="placeholder">
      <slot></slot>
    </div>
    <div class="ar-list__bottom">{
    
    {
    
    statusText}}</div>
  </div>
</template>

修改触底逻辑:

  private handleScroll(){
    
    
    if(this.isLoadMore || this.isFinished) return;

    let scrollerRect;
    if (this.scrollEl.getBoundingClientRect) {
    
    
      scrollerRect = this.scrollEl.getBoundingClientRect();
    } else {
    
    
      scrollerRect = {
    
    
        top: 0,
        bottom: this.scrollEl.innerHeight
      };
    }

    const scrollerHeight = scrollerRect.bottom - scrollerRect.top;
    if(!scrollerHeight) return;

    const placeholderRect = this.placeholder.getBoundingClientRect();
    if(placeholderRect.bottom - scrollerRect.bottom <= (+this.offset)){
    
    
      this.$emit('loadMore');
    }
 }

最后

感谢阅读~

猜你喜欢

转载自blog.csdn.net/qq_34086980/article/details/108631147