最近在研究vuejs上拉加载更多实现方案,上网找了下这方面的文章和代码貌似不是太多,而且逻辑实现并不太清晰,于是自己结合了前人的经验自己整合了下总结下经验.
上拉加载更多实现思路最关键的就是如何识别手指滑动操作,如果不是用vuejs,可以用html的onscroll函数来监听滑动的位置来实现,如果是基于vuejs,直接在标签里用onscroll事件是没用,这个具体没有研究清楚.下面就讲讲vuejs的方案,先贴出代码:

//scroll.vue
<template lang="html">
    <div class="yo-scroll"  @touchstart="touchStart($event)"
         @touchmove="touchMove($event)" @touchend="touchEnd($event)" >
        <section class="inner">
            <!-- 使用时外面的标签会填在里面 -->
            <slot>
            </slot>
            <!-- 保持加载更多条在最下面 -->
            <footer class="load-more">
                <slot name="load-more">
                    <span>{{loadMoreText}}</span>
                </slot>
            </footer>
            <div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
        </section>
    </div>
</template>
<style lang="less">
    /*:class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"*/
    .yo-scroll {
        font-size: 24px;
        position: absolute; //关键
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        overflow: auto; //关键
        z-index: 100;
        height: auto;
        -webkit-overflow-scrolling: touch;
        .inner { position: absolute;
            /*top: -5rem;*/
            width: 100%;
            height: auto;
            transition-duration: 300ms;
            .load-more { height: 5rem;
                line-height: 5rem;
                display: flex;
                text-align: center;
                align-items: center;
                justify-content: center;
                display: none;
            }
            .nullData {//暂无更多数据样式
                font-size: 26px;
                color: #999999;
                height: 100px;
                line-height: 100px;
                text-align: center;
            }
            .down-tip,
            .refresh-tip,
            .up-tip {
                display: none;
            }
        }
    }

    .yo-scroll.touch .inner {
        transition-duration: 0;
    }

    .yo-scroll.down .down-tip {
        display: block;
    }

    .yo-scroll.up .up-tip {
        display: block;
    }

    .yo-scroll.refresh .refresh-tip {
        display: block;
    }
</style>
<script>
    export default {
        props: {
            offset: {
                type: Number,
                default: 100 //默认高度
            },
            enableLoadMore: {
                type: Boolean,
                default: true
            },
            dataList: {
                default: false,
                required: false
            },
            onLoadMore: {
                type: Function,
                default: undefined,
                require: false
            }
        },
        data() {
            return {
                startX: 0,
                startY: 0,
                touching: false,
                isLoading: false,
                loadMoreText: "上拉加载更多"
            }
        },
        methods: {
            touchStart(e) {
                this.startY = e.targetTouches[0].pageY;
                this.startX = e.targetTouches[0].pageX;
                this.startScroll = this.$el.scrollTop || 0;
                this.touching = true; //留着有用,不能删除
                this.dataList.noFlag = false;

            },
            //滑动中
            touchMove(e) {
                if(!this.enableLoadMore || this.dataList.noFlag || !this.touching) {
                    return
                }
                let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
                if(diff > 0) {
                    e.preventDefault()
                }
                this.loadMoreText = '上拉加载更多'
                this.$el.querySelector('.load-more').style.display = 'block';
            },

            touchEnd(e) {
              if (this.isLoading) {
                    return;
                }
                this.touching = false

                //用于判断滑动是否在原地 ----begin
                let endX = e.changedTouches[0].pageX,
                    endY = e.changedTouches[0].pageY,
                    dy = this.startY - endY,
                    dx = endX - this.startX;

                //如果滑动距离太短
                if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
                    // console.log("滑动距离太短")
                    let more = this.$el.querySelector('.load-more')
                    more.style.display = 'none'; //隐藏加载条
                    return;
                }

                if(!this.enableLoadMore || this.isLoading) {
                    let more = this.$el.querySelector('.load-more')
                    more.style.display = 'none'; //隐藏加载条
                    return
                }

                let outerHeight = this.$el.clientHeight,
                    innerHeight = this.$el.querySelector('.inner').clientHeight,
                    scrollTop = this.$el.scrollTop,
                    bottom = innerHeight - outerHeight - scrollTop;

                if(bottom <= this.offset) {
                    //内容太少
                    this.doLoadMore();
                } else {
                    let more = this.$el.querySelector('.load-more')
                    more.style.display = 'none'; //隐藏加载条
                }
            },

            doLoadMore() {
                this.isLoading = true
                this.loadMoreText = '正在加载'
                this.onLoadMore(this.loadDone);
            },

            loadDone() {
                this.isLoading = false
                let more = this.$el.querySelector('.load-more')
                more.style.display = 'none'; //隐藏加载条

            }
        }
    }
</script>

这里是使用组件的方式实现, @touchstart=”touchStart( event)"@touchmove="touchMove( e v e n t ) " @ t o u c h m o v e =" t o u c h M o v e ( event)” @touchend=”touchEnd($event) 为布局加上滚动事件,具体实现在script里,touchStart先记录手指按下坐标,touchmove记录手指滑动的距离,判断是否显示更多条,touchEnd判断是否触发加载更多事件,一但达到条件就调用外面传进来的onLoadMore函数,通过外面的调用done来控制是否完成.实现的效果是上拉时显示”下拉加载更多”,手指释放时显示”正在加载”,完成后隐藏控制条.
外面使用的组件代码 :

<template>
  <div>
    <v-scroll :onLoadMore="onLoadMore" :dataList="scrollData">
      <ul>
        <li v-for="(item) in listdata" :key="item.name">{{item.name}}</li>
        <li v-for="(item) in downdata" :key="item.name">{{item.name}}</li>
      </ul>
    </v-scroll>
  </div>
</template>
<style lang="less">
  ul li {
    min-height: 100px;
    line-height: 100px;
    text-align: center;
    border: 1px solid red;
  }
</style>
<script>
  import loadmore from "./scroll.vue";
    export default {
        components: {
            'v-scroll': loadmore
        },
        data() {

            return {
                counter: 1, //当前页
                num: 10, // 一页显示多少条
                pageStart: 0, // 开始页数
                pageEnd: 0, // 结束页数
                listdata: [], // 下拉更新数据存放数组
                downdata: [], // 上拉更多的数据存放数组
                scrollData:{
                    noFlag: false //暂无更多数据显示
                }
            }
        },
        mounted: function() {
            this.getList();
        },
        methods: {
            getList() {
                var response = []
                for(let i = 0; i < 60; i++) {
                    response.push({
                        name: i
                    })
                }
                this.listdata = response.slice(0, this.num);
            },

            onLoadMore(done) {
                this.counter++;
                let end = this.pageEnd = this.num * this.counter;
                let i = this.pageStart = this.pageEnd - this.num;

                setTimeout(() => {
                    for(i; i < end; i++) {
                        if(i >= 30) {
                            //走完数据调用方法
                            // this.scrollData.noFlag = true;
                            break;
                        } else {
                            this.downdata.push({
                                name: i + "==="
                            })
                            // more.style.display = 'none'; //隐藏加载条
                        }
                    }
                    done();
                }, 2000);
            }
        }

    }
</script>

实现的完整代码在github上可以找到:https://github.com/Cmdmac/vuejs-loadmore.git

Logo

前往低代码交流专区

更多推荐