移动端滚动加载更多组件 - loadermore

移动端滚动加载更多组件

前言

之前在移动端需求的时候,有个功能点就是关于滚动加载,滚动到底部以后,自动执行下次请求。本来想着使用公司内部基础组件的,但是发现基础组件没有(内部一般禁止引入一些大公司的组件,风险问题)。

看了其他开源的单组件,写的都挺好的,但是整体代码量较多,内心是存在排斥心理的,所以...

没办法,只能手撸了~

实现

配置
配置 默认值 备注
pageIndex 1 分页请求 index
pageSize 10 分页请求 size
totalCount 0 分页请求 count
delay 500(ms) 延迟请求
bottom 25 滚动条到达底部多少就会自动请求数据
fail False 请求失败需要让组件知道,为 true,则更改提示
failTips '请求失败,稍候重试!' 请求失败需要展示的信息
原理

监听滚动,当滚动到用户配置的 bottom 时,执行下次请求,当请求完毕,不执行请求。当请求失败时,提示组件请求失败,增加提示失败信息。

代码
<template>
  <div
    id="loadMore"
    class="loadmore"
  >
    <slot></slot>
    <div
      class="loadmore-tip"
      id="loadTips"
      v-if="totalCount > 0 && totalCount >= pageSize"
    >
      <i
        v-show="loadTips=='正在加载中'"
        class="loadmore-icon"
      ></i>
      {{loadTips}}
    </div>
  </div>
</template>
<script>
let timer = null // 不作为响应式变量,提升性能
export default {
    props: {
        pageIndex: {
            type: Number,
            default: 1
        },
        pageSize: {
            type: Number,
            default: 10
        },
        totalCount: {
            type: Number,
            default: 0
        },
        delay: {
            type: [Number],
            default: 500
        },
        // 滚动条到达底部多少就会自动请求数据
        bottom: {
            type: [Number],
            default: 25
        },
        // 请求失败预防针,测试中发现的这个
        fail: {
            type: Boolean,
            default: false
        },
        failTips: {
            type: String,
            default: '请求失败,稍候重试!'
        }
    },
    data () {
        return {
            loadTips: '正在加载中'
        };
    },
    watch: {
        pageIndex () {
            this.loadMore()
        },
        totalCount: {
            handler (val, oldval) {
                if (val > 0) {
                    this.loadMore()
                }
            },
            // 首次请求
            immediate: true
        },
        fail (value) {
            if (value) {
                this.loadTips = this.failTips
            }
        }
    },
    methods: {
        // 上滑动加载更多
        loadMore () {
            this.loadTips = '正在加载中';
            const {pageSize, pageIndex, totalCount} = this
            return new Promise((resolve, reject) => {
                window.onscroll = () => {
                    timer = setTimeout(() => {
                        if (!document.getElementById('loadTips')) return
                        const clientHeight = document.documentElement.clientHeight || document.body.clientHeight || 0
                        const rectBottom = document.getElementById('loadTips').getBoundingClientRect().bottom || 0
                        if (rectBottom < clientHeight + this.bottom) {
                            const size = totalCount - pageIndex * pageSize
                            if (size > 0) {
                                this.$emit('loadmore', pageIndex + 1)
                                resolve(true)
                            } else {
                                this.loadTips = '没有更多数据了'
                                resolve(false)
                            }
                            clearTimeout(timer)
                        }
                    }, this.delay)
                }
            })
        }
    },
    beforeDestroy () {
        clearTimeout(timer)
    }
};
</script>
<style lang="scss" scoped>
.loadmore-tip {
  color: #aaa;
  font-size: 12px;
  text-align: center;
  height: 40px;
  line-height: 40px;
}

@keyframes rotate-loading {
  0% {
    -webkit-transform: rotate(0);
    transform: rotate(0);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-webkit-keyframes rotate-loading {
  0% {
    -webkit-transform: rotate(0);
    transform: rotate(0);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
.loadmore-icon {
  vertical-align: -2px;
  width: 12px;
  height: 12px;
  display: inline-block;
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAGzUExURUxpcaSmo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo6Smo7OajWMAAACQdFJOUwDzVSjxAgf0ChUBCd/hpyn6+ai70Qz1uB92XuuOR5xNbnBc0ulZd4eNIdsW/myUA1iBhMgnbQiWb7zsJM/l1hqqFEjOqQ3GrbH4LGQrr/CK49NdjIncrLNiaRtbtRl1771FUHjQj0aQBt5axWCTHeRmt57dnbTyg6vV7eIgEk4mUdcwOvceDgQRiPylmZgL2vNJv00AAAM1SURBVFjDrZl3WxpBEMaPQ3ovKiAKSreABREVLLEbTewaY4mJJb333nvhIwd2jqNzbeYvHnb2d+zd7Du3LxRVPyaPeqK2Mb8sY3n5yG6L9hxNUuJD7Tk57s6URffxiUcthqZoNaoyNUJlbFUIxDW26zN1Q9/eKACnO2jJcEaLU8eX12sontiUmu5P7tD0TrJ/OtVUPGLo5YVzPChMaZhPLmqLB7WL3vmGwnizg5vXweab9+iqi9LRe2b2ih0cuMRj9km6d2un7brZCniYqMfrmmXSLBua+lfWbFiY1Nmu2lmRTSZpOM59b+LDTPJmpFaKKQ0ZMhe/anDJID9tqj4+ugLjq3K+9SVfhRkro1XvSieMWgXsVJ0R5nRWuePXB2AsrBWyRbXrMGtAWTHUBiN9QkWkD+a1VdQzfD8kXJaGYGZZhTtgf8zFhANjW7BnSndhM/nSJ0o51T7Y1yX6AvUnF6fscqjHQNE1QK9clMhwgZoV1ueE/Sa++zwhACer90SfF+TigZHPOcJIvisMEv5FCf2RChHEINPfbhCl10gBaog+6qEXthK6m5IU7ixi4hN8JhvcPC4NOH4Y/pKvGfJr5yiJ8Y39dJWs+C2FFn9yvAtKPOC/HHACj9dFVnweD3iOAE14wGukqhV4QCL9djwedYV0OkTghxwwhAj054BBRODTHPASIpBUzWVEoAUbOIK9ZD32Q/Fhlw16YaNvPXRxQJcvdIGlOpFbAPUbu0lBG/XgAf+SRr+FuGYrxqtIZeG48YAKog+qSTwiwgtnmQVCNHEhjkeEl3YbHpA5VqzhEQOSDj7VAo5mdjUa8DUcHp/H0Ihroo+3dVuBiAN4zVAyFsG6FouYNzGMCSzi6D0g+tCqx/RKmBHEHXdfMO6T7R2PIy2fTvnmVt5MC3GZaT8sqe98nvUd1u4L79dO2w9n+8bPX1/5LPv9IWtIbtNVe6GS3mYMyQNeN9LRXGSZLnuXSi3TJe9ywTJNf+SpPSWmrmrK+sx7m755P9hvnSqxtg0Bvk9b5+RjOwd1AgpohtsYnxHaC3Gte+gMnjN75Z8L9jOPFB3WnJK/P7I/VuUfs0V7TrncmP8jtvO4FdRBjgAAAABJRU5ErkJggg==")
    no-repeat;
  background-size: 12px 12px;
  -webkit-animation: rotate-loading 0.5s linear forwards infinite;
  animation: rotate-loading 0.5s linear forwards infinite;
}
</style>
  • 分享

    有什么新发现就分享给大家吧!

    230 引用 • 1666 回帖 • 97 关注
  • Vue.js

    Vue.js(读音 /vjuː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    223 引用 • 638 回帖 • 486 关注
  • 代码
    443 引用 • 542 回帖 • 6 关注

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...