写在前面

搜罗全网,终于找到一个好用的Vue滑动组件,包括上拉加载,下拉刷新等一大堆好用的方法,他就是mescroll组件,由于很多个页面都需要用到mescroll组件,所以自己把他封装成了一个组件,方便自己使用

mescroll组件

<template>
  <div class="mescroll-wrap">
    <mescroll ref="mescroll" :down="down" :up="up" @init="init">
      <!-- 列表 -->
      <slot></slot>
    </mescroll>
  </div>
</template>

<script>
  import mescroll from 'mescroll.js/mescroll.vue'

  export default {
    props: {
      // 无数据提示 非必需
      emptyText: {
        type: String,
        default () {
          return '暂无相关数据'
        }
      },
      // 显示noMore条数据就显示“没有更多数据了” 非必需
      noMore: {
        type: Number,
        default () {
          return 10
        }
      },
      // 每页多少条
      pageSize: {
        type: Number,
        default () {
          return 10
        }
      },
      // 父ID 必需
      warpId: {
        type: String,
        default () {
          return null
        }
      },
      // 下拉刷新的位置 非必需
      downRefresh: {
        type: String,
        default () {
          return null
        }
      },
      // 回顶部时间 非必需
      topTime: {
        type: Number,
        default () {
          return 4
        }
      },
      downText: {
        type: Object,
        default () {
          return {
            textInOffset: "<i class='iconfont icon-shang-copy'></i><span>下拉刷新</span>",
            textOutOffset: "<i class='iconfont icon-shang-copy-copy'></i><span>松开刷新</span>",
            textLoading: '加载中...'
          }
        }
      },
      btntext: {
        type: String,
        default () {
          return null
        }
      }
    },
    data () {
      return {
        mescroll: null,
        down: {
          offset: 50,
          auto: false,
          hardwareClass: 'mescroll-hardware',
          resetClass: 'mescroll-downwarp-reset',
          warpClass: 'mescroll-downwarp',
          mustToTop: true,
          warpId: this.downRefresh,
          callback: this.downCallback,
          ...this.downText, // 下拉刷新文字
          htmlContent: `<div class="downwarp-onload">
                          <p class="downwarp-progress"></p>
                          <p class="downwarp-tip">加载中…</p>
                        </div`
        },
        up: {
          offset: 0,
          hardwareClass: 'mescroll-hardware',
          warpClass: 'mescroll-upwarp',
          isBounce: true,
          callback: this.upCallback,
          htmlNodata: "<p class='upwarp-nodata'>没有更多数据啦…</p>",
          toTop: {
            warpId: this.warpId, // mescroll
            src: require('./image/火箭.png'), // 回顶图标路径
            offset: 400, // 滑动多少距离才显示回顶图标
            duration: this.topTime, // 页面回顶时间
            warpClass: 'mescroll-totop', // 返回顶部按钮class名
            showClass: 'mescroll-fade-in', // 返回顶部按钮进入class名
            hideClass: 'mescroll-fade-out', // 返回顶部按钮隐藏class名
            btnClick: this.btnClick
          },
          htmlLoading: '<p class="upwarp-progress mescroll-rotate"></p><p class="upwarp-tip">加载中…</p>',
          lazyLoad: {
            use: true, // 开启懒加载
            attr: 'imgurl', // 网络图的自定义属性名
            showClass: '', // 懒加载图片展示方式
            // mescroll-lazy-in
            delay: 50, // 延时时间
            offset: 50 // 滑动时离底部多少距离才开始展示图片
          },
          empty: {
            // 列表第一页无任何数据时,显示的空提示布局; 需配置warpId才显示
            warpId: this.warpId, // 父布局的id (1.3.5版本支持传入dom元素)
            icon: require('./image/no.png'), // 图标,默认null,支持网络图
            tip: this.emptyText, // 提示
            btntext: this.btntext,
            btnClick: this.btntext ? this.btnClick : null
          },
          noMoreSize: this.noMore,
          onScroll: this.onScroll,
          page: {
            size: this.pageSize
          }
        }
      }
    },
    components: {
      mescroll
    },
    methods: {
      // mescroll组件初始化的回调,可获取到mescroll对象
      init (mescroll) {
        this.mescroll = mescroll
      },
      downCallback () {
        if (this.warpId !== 'chat-wrap') {
          this.$parent.page.page = 1
        }
        this.$parent.page.pageSize = 10
        // 下拉刷新不至于太快
        let timer = setTimeout(() => {
          this.$emit('getData')
          clearTimeout(timer)
        }, 500)
      },
      // 上拉回调
      upCallback () {
        // if (this.$parent.page.page === 2) return
        this.$emit('getData')
      },
      // 获取记录的滚动位置
      getTop () {
        this.$refs.mescroll && this.$refs.mescroll.beforeRouteEnter()
      },
      // 记录位置
      setTop () {
        this.$refs.mescroll && this.$refs.mescroll.beforeRouteLeave()
      },
      onScroll (mescroll, y, isUp) {
        this.$parent.y = y
        this.y = y
        this.isUp = isUp
        this.$emit('onScroll', y, isUp)
      },
      // 点击图片回到顶部方法,加计时器是为了过渡顺滑
      btnClick () {
        this.isUp = false
        let timer = setInterval(() => {
          let ispeed = Math.floor(-this.y / (this.topTime + 1))
          this.$refs.mescroll.$refs.mescroll.scrollTop = this.y + ispeed
          if (this.y === 0 || this.isUp) {
            clearInterval(timer)
          }
        }, 16)
        return true
      }
    }
  }
</script>

<style lang="less">
  // iconfont的上箭头和下箭头
  @import '//at.alicdn.com/t/font_1190508_vm3jx9rejm.css';

  // 无数据按钮
  .mescroll-empty .empty-btn {
    top: 26/75rem;
    min-width: 40%;
    max-width: 50%;
    margin: 20/75rem auto;
    padding: 24/75rem 20/75rem;
    border: 0;
    border-radius: 8/75rem;
    background-color: #f95644;
    color: #fff;
    position: relative;
    z-index: 10;
    font-size: 28/75rem;
  }
  // 没有更多数据啦
  .upwarp-nodata{
    padding: 16px 0;
  }
  // 下拉刷新上下距离
  .downwarp-onload{
    margin-top: -6px;
  }
  // 上拉加载loading上下距离
  .mescroll-upwarp, .mescroll-hardware {
    padding: 0 0;
  }
  .downwarp-content{
    padding: 0!important;
  }
  // 下拉刷新文字
  .downwarp-tip{
    margin-left: 2px!important;
    .iconfont{
      font-size: 38/75rem;
      color: rgb(158, 158, 158);
      margin-right: @12px;
      vertical-align: middle;
    }
  }
  .downwarp-progress{
    display: none!important;
    &.mescroll-rotate{
      display: inline-block!important;
      background-size: contain;
      animation: progressRotate .8s steps(12, end) infinite;
    }
  }
  .upwarp-progress{
    background-size: contain;
    animation: progressRotate .8s steps(12, end) infinite;
  }
  .mescroll-downwarp .downwarp-progress,
  .mescroll-upwarp .upwarp-progress{
    width: 24px;
    height: 24px;
    border: none;
    margin: auto;
    background-size: contain;
    background-image: url('./image/loading.svg');
  }
  .upwarp-progress{
    margin: 12px 0 !important;
  }
  @keyframes progressRotate {
    0% {
      -webkit-transform: rotate3d(0, 0, 1, 0deg);
      transform: rotate3d(0, 0, 1, 0deg);
    }
    100% {
      -webkit-transform: rotate3d(0, 0, 1, 360deg);
      transform: rotate3d(0, 0, 1, 360deg);
    }
  }
  
  .mescroll-wrap{
    .mescroll-sticky{
      position: sticky;
      top: -1px;
      z-index: 5;
      background: #fff;
    }
    .mescroll-totop:active{
      opacity: 0.7;
    }
    .mescroll-fade-in {
      transition: all linear .3s;
    }

    .mescroll-fade-out {
      transform: translateY(40px);
      transition: all linear .3s;
      opacity: 0;
    }
    .mescroll {
      position: absolute;
      z-index: 2;
      height: auto;
    }
  }
</style>

*loading图片链接

调用方法

<template>
  <div id='parentId'>
    <mescroll
    ref="mescroll"
    @getData='getData()'
    warpId='parentId'
    emptyText='空数据提示' >        
        <!-- 内容 -->
    </mescroll>
  </div>
</template>

<script>
  import mescroll from '@/base/mescroll/mescroll'

  export default {
    data () {
      return {
        list: [],
        // 定义page
        page: {
          page: 1,
          pageSize: 10
        }
      }
    },
    beforeRouteEnter (to, from, next) {
      next(vm => {
        vm.$refs.mescroll.getTop() // 返回页面保留原位置,路由需加keep-alive
      })
    },
    beforeRouteLeave (to, from, next) {
      this.$refs.mescroll.setTop() // 离开页面记住位置,路由需加keep-alive
      next()
    },
    created () {
    },
    methods: {
      getData () {
        if (this.page.page === 1) {
          this.list = []
        }
        getActivity().then((res) => {
          // 请求接口,返回的数据
          this.list = [...this.list, ...res.data.list]
          this.page.page += 1
          // 传递参数,本页的数据、是否有下一页
          this.$nextTick(() => {
            // 后台返回hasNextPage告知是否有下一页,或者前端这边自己判断
            this.$refs.mescroll.mescroll.endSuccess(res.data.list.length, res.data.hasNextPage)
          })
        })
      }
    }
  }
</script>
<style lang="less" scoped>
  @import '../../../../common/less/pixel.less';
  /deep/.mescroll {
    position: absolute;
    top: 176/75rem;
    bottom: 98px/75rem;
    z-index: 2;
    height: auto;
  }
  /deep/.mescroll-empty {
    padding-top: 450/75rem;
  }
</style>

有问题,请指正,谢谢?

Logo

前往低代码交流专区

更多推荐