vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件

1.下拉刷新和上拉加载更多组件

Scroller.vue

<!-- 下拉刷新 上拉加载更多 组件 -->
<template>
  <div
    :style="marginTop"
    class="yo-scroll"
    :class="{‘down‘:(state===0),‘up‘:(state==1),refresh:(state===2),touch:touching}"
    @touchstart="touchStart($event)"
    @touchmove="touchMove($event)"
    @touchend="touchEnd($event)">
    <section class="inner" :style="{ transform: ‘translate3d(0, ‘ + top + ‘px, 0)‘ }">
      <!-- 顶部提示语(刷新) -->
      <header class="pull-refresh">
        <slot name="pull-refresh">
          <span class="down-tip">下拉更新</span>
          <span class="up-tip">松开刷新数据</span>
          <span class="refresh-tip">加载中……</span>
        </slot>
      </header>
      <!-- 父组件 列表部分 -->
      <slot>
      </slot>
      <!-- 底部提示语(加载更多) -->
      <footer class="load-more">
        <slot name="load-more">
          <span v-show="downFlag === false">上拉加载更多</span>
          <span v-show="downFlag === true">加载中……</span>
        </slot>
      </footer>
      <!-- 暂无数据提示语 -->
      <div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
    </section>
  </div>
</template>

<script>
  export default {
    // 接收父组件参数
    props: {
      marginTop: {
        default: "margin-top:40px;"
      },
      // 默认高度
      offset: {
        type: Number,
        default: 100
      },
      // 是否支持加载更多
      enableInfinite: {
        type: Boolean,
        default: true
      },
      // 是否支持刷新
      enableRefresh: {
        type: Boolean,
        default: true
      },
      // 是否显示‘暂无数据‘
      dataList: {
        default: false,
        required: false
      },
      // 刷新方法
      onRefresh: {
        type: Function,
        default: undefined,
        required: false
      },
      // 加载更多方法
      onInfinite: {
        type: Function,
        default: undefined,
        require: false
      }
    },
    data() {
      return {
        top: 0, // 下拉高度
        state: 0, // 状态: 0 下拉/ 1 上拉 / 2 刷新
        startX: 0, // 手指滑动起始位置 X轴
        startY: 0, // 手指滑动起始位置 Y轴
        touching: false, // -webkit-overflow-scrolling
        infiniteLoading: false, // 加载更多效果
        downFlag: false, //用来显示是否加载中
      }
    },
    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; // 默认 不显示‘暂无数据‘
        this.$el.querySelector(‘.load-more‘).style.display = ‘block‘;// 实体化加载更多
      },
      // 手指移动中
      touchMove(e) {
        if(!this.enableRefresh || this.dataList.noFlag || !this.touching) {
          return
        }
        let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
        if(diff > 0) e.preventDefault()
        this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
        if(this.state === 2) { // 刷新中
          return
        }
        if(this.top >= this.offset) {
          this.state = 1
        } else {
          this.state = 0
        }
        let more = this.$el.querySelector(‘.load-more‘);
        if(!this.top && this.state === 0) {
          more.style.display = ‘block‘;
        } else {
          more.style.display = ‘none‘;
        }
      },
      // 手指结束滑动
      touchEnd(e) {
        if(!this.enableRefresh) {
          return
        }
        this.touching = false
        if(this.state === 2) { // 刷新中
          this.state = 2
          this.top = this.offset
          return
        }
        if(this.top >= this.offset) { // 进行刷新
          this.refresh()
        } else { // 取消刷新
          this.state = 0
          this.top = 0
        }
        //用于判断滑动是否在原地 ----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("滑动距离太短")
          return;
        }
        //--------end--------
        if(!this.enableInfinite || this.infiniteLoading) {
          return
        }
        let outerHeight = this.$el.clientHeight,
          innerHeight = this.$el.querySelector(‘.inner‘).clientHeight,
          scrollTop = this.$el.scrollTop,
          ptrHeight = this.onRefresh ? this.$el.querySelector(‘.pull-refresh‘).clientHeight : 0,
          bottom = innerHeight - outerHeight - scrollTop - ptrHeight;
        if(bottom <= this.offset && this.state === 0) {
          this.downFlag = true;
          this.infinite();
        } else {
          this.$el.querySelector(‘.load-more‘).style.display = ‘none‘;
          this.downFlag = false;
        }
      },
      // 刷新
      refresh() {
        this.state = 2;
        this.top = this.offset;
        setTimeout(() => {
          this.onRefresh(this.refreshDone)
        }, 300);
      },
      // 结束刷新
      refreshDone() {
        this.state = 0
        this.top = 0
      },
      // 加载更多
      infinite() {
        this.infiniteLoading = true
        setTimeout(() => {
          this.onInfinite(this.infiniteDone);
        }, 2000);
      },
      // 结束加载更多
      infiniteDone() {
        this.infiniteLoading = false
      }
    }
  }
</script>

<style lang="less" scoped>
  .yo-scroll {
    // margin-top: 40px; // 解决有标题栏的bug
    font-size: 16px;
    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: -50px;
      width: 100%;
      height: auto;
      transition-duration: 300ms;
      .pull-refresh {
        position: relative;
        left: 0;
        top: 0;
        width: 100%;
        height: 50px;
        display: flex;
        display: -webkit-flex;
        align-items: center;
        justify-content: center;
      }
      .load-more {
        height: 50px;
        line-height: 50px;
        display: flex;
        text-align: center;
        align-items: center;
        justify-content: center;
        display: none;
      }
      .nullData { //暂无更多数据样式
        font-size: 16px;
        color: #999999;
        height: 50px;
        line-height: 60px;
        text-align: center;
      }
      .down-tip,
      .refresh-tip,
      .up-tip {
        display: none;
      }
      .up-tip:before,
      .refresh-tip:before {
        content: ‘‘;
        display: inline-block;
        width: 110px;
        height: 40px;
        font-size: 16px;
        background-size: 70% !important;
        position: absolute;
        top: 0;
        left: 20%;
      }
      .up-tip:before {
        background: url(../assets/images/down-logo.png) no-repeat left;
      }
      .refresh-tip:before {
        background: url(../assets/images/refresh-logo.gif) no-repeat left;
      }
    }
  }

  .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>

2.页面调用

LoadMore.vue

<!-- 加载更多 -->
<template>
  <div>
    <!-- 标题栏 -->
    <mt-header title="加载更多">
      <router-link to="/" slot="left">
        <mt-button icon="back">返回</mt-button>
      </router-link>
    </mt-header>
    <!-- 列表 -->
    <div class="cont">
      <m-scroller :on-refresh="onRefresh" :on-infinite="onInfinite" :dataList="scrollData" :marginTop="marginTop">
        <ul>
          <li v-for="(item,index) in listdata">{{item.name}}</li>
        </ul>
      </m-scroller>
    </div>
  </div>
</template>

<script>
  import mScroller from ‘../components/Scroller‘

  export default {
    components: {
      mScroller
    },
    data() {
      return {
        marginTop:‘margin-top:40px;‘,
        pageStart: 0, // 开始页数
        pageEnd: 0, // 结束页数
        listdata: [], // 数据列表
        scrollData:{
          noFlag: false //暂无更多数据显示
        }
      }
    },
    mounted: function() {
      // 首次请求数据
      this.fetchData();
    },
    methods: {
      fetchData() {
        this.axios.get(‘/api/testData‘).then((response) => {
          this.listdata = response.data.data.list;
          // 获取总页数
          this.pageEnd = response.data.data.totalPage;
          // 还原
          this.pageStart = 0;
        })
      },
      // 下拉刷新
      onRefresh(done) {
        this.fetchData();
        done(); // call done
      },
      // 上拉加载更多
      onInfinite(done) {
        this.pageStart++;
        // 加载条
        let more = this.$el.querySelector(‘.load-more‘);
        // 判断是否显示加载条
        if(this.pageStart > this.pageEnd){
          //走完数据调用方法
          this.scrollData.noFlag = true;
        }else{
          let _this = this;
          this.axios.get(‘/api/testData‘).then((response) => {
            _this.listdata = _this.listdata.concat(response.data.data.list);
            // 获取总页数
            _this.pageEnd = response.data.data.totalPage;
          })
        }
        // 隐藏加载条
        more.style.display = ‘none‘;
        done();
      }
    }
  }
</script>

<style lang="less" scoped>
  ul {
    li {
      min-height: 50px;
      line-height: 50px;
      text-align: center;
      border: 1px solid red;
    }
  }
  // 隐藏滚动条
  ::-webkit-scrollbar{
    display:none;
  }
</style>

3.效果图

时间: 2024-11-11 04:13:05

vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件的相关文章

支持下拉刷新和上划加载更多的自定义RecyclerView(仿XListView效果)

首先看效果 下拉刷新:        上划加载        在项目更新的过程中,遇到了一个将XListView换成recyclerView的需求,而且更换完之后大体效果不能变,但是对于下拉刷新这样的效果,谷歌给出的解决方案是把RecyclerView放在一个SwipeRefreshLayout中,但是这样其实是拉下一个小圆形控件实现的,和XListView的header效果不同.在网上找了很多的别人代码,都没有实现我想要的效果,于是自己动手写了一个. 具体实现的效果有以下几条 下拉刷新功能:

Android下拉刷新库,利用viewdraghelper实现,集成了下拉刷新,底部加载更多,数据初始加载显示loading等功能

项目Github地址:https://github.com/sddyljsx/pulltorefresh Android下拉刷新库,利用viewdraghelper实现. 集成了下拉刷新,底部加载更多,以及刚进入加载数据的loadview.包括了listview与gridview的改写. 效果1: 效果2: 效果3: 效果4: 效果5: 使用说明: imageList=(ListView)findViewById(R.id.image_list); imageAdapter=new ImageA

IOS学习之UiTableView下拉刷新与自动加载更多,百年不变的效果

IOS学习之UiTableView下拉刷新与自动加载更多,百年不变的效果(五) 五一劳动节马上来临,小伙伴有妹有很激动哟,首先祝天下所有的程序猿节日快乐!这个五一对于我来说有点不一样,我的人生从这个五一就转弯了,爱情长跑8年的我结婚了,一会支付宝账号我会公布出去,请自觉打款!谢谢合作. 灯光闪起来: 舞蹈跳起来: 歌曲唱起来: -------------------------------------------------------------------------------------

Android ListView 下拉刷新 点击加载更多

最近项目中用到了ListView的下拉刷新的功能,总结了一下前辈们的代码,单独抽取出来写了一个demo作为示例. 效果图 下拉刷新: 加载更多: CustomListView.java [java] view plaincopy package com.example.uitest.view; import java.util.Date; import com.example.uitest.R; import android.content.Context; import android.uti

十分钟实现ListView下拉刷新上滑加载更多

说到ListView下拉刷新几乎每个APP都会用到,所以ListView下拉刷新是很重要的,就像ListView优化一样是你必会的东西. ListView实现下拉刷新如果我们开发人员自己编写相对来说比较费事的,当我们使用第三方库之后我们再来开发这个功能就会省事很多.相比与自己实现可以少编写不少代码,Android-PullToRefresh库可以轻松实现ListView的下拉刷新功能. 要使用Android—PullToRefesh库对ListView实现下拉刷新要经过以下几个步骤: 1.下载A

最新Android ListView 下拉刷新 上滑加载

开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,之前大家最常用的应该是pull to refresh或它的变种版吧,google官方在最新的android.support.v4包中增加了一个新类SwipeRefreshLayout,地址 这个类的作用就是提供官方的下拉刷新,并且效果相当不错,而上拉加载更多则用我们自定义的listview,也是相当简单. 下拉刷新 简单的介绍下: 首先它是一个viewgroup,但是它只允许有一个子控件,子控件能是任何view,使用的时候,所在

Android 自定义 ListView 上下拉动&ldquo;刷新最新&rdquo;和&ldquo;加载更多&rdquo;歌曲列表

本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码太多,点击此处下载,自己调试一下. 下载 Demo 环境 Windows 2008 R2 64 位 Eclipse ADT V22.6.2,Android 4.4.3 SAMSUNG GT-I9008L,Android OS 2.2.2 测试数据 本演示的歌曲信息,共有 20 条,包括歌手名.歌曲名.时长.缩

自定义下拉刷新和上拉加载的recycleview

自定义下拉刷新和上拉加载的recycleview 先看一下效果(因为模拟器的原因,看不到进度条,大家可以下载demo,进行查看) demo地址 首先看我们自定义的HeadView package yuan.kuo.yu.view; import android.animation.ValueAnimator; import android.content.Context; import android.os.Handler; import android.util.AttributeSet; i

Android实现RecyclerView的下拉刷新和上拉载入很多其它

需求 先上效果图, Material Design风格的下拉刷新和上拉载入很多其它. 源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2 假设对于RecyclerView还不熟悉,參见这篇 Android Material Design学习之RecyclerView取代 ListView 本文链接 http://blog.csdn.net/never_cxb/article/details/50759109 转载请注明出处 下拉刷新 效果图