Vue项目中的上拉加载和下拉刷新


在移动端的项目中,由于显示器容量的限制,经常会有许多滚动场景的需求,因此Vue项目中实现列表的上拉加载和下拉刷新是非常频繁的事情,但是在真正项目中前端对于这个的实现有非常多的坑,今天主要介绍Vue项目中插件cube-scroll、better-scroll和mescroll的使用以及滚动场景中的业务逻辑设计。

在了解这些滚动插件之前,我们首先需要知道👉浏览器的滚动原理
浏览器的视口的宽高是有限的,当页面的内容高度超过视口高度(contentHeight > viewHeight)的时候,会出现纵向滚动条;同样地,当页面的内容宽度超过视口宽度(contentWidth > viewWidth)的时候,会出现横向滚动条。总之就是当视口展示不下页面上内容的时候,会通过滚动条的形式让用户看到剩余的内容。

scroll的滚动原理content是被列表内容弹性撑开的,超过了父容器的宽度(高度)才得以滚动。

Better-Scroll——基于iScroll的重写和实现

Better-Scroll的文档
应用场景: 滚动列表、轮播图、picker

1. 初始化better-scroll

import BScroll from 'better-scroll'
let wrapper = document.querySelector('.wrapper')
let scroll = new BScroll(wrapper, {}) // 初始化就是new一个BScroll类的实例

better-scroll 的初始化时机很重要,因为它在初始化的时候,会计算父元素和子元素的高度和宽度,来决定是否可以纵向和横向滚动。因此,我们在初始化它的时候,必须确保父元素和子元素的内容已经正确渲染了。如果子元素或者父元素 DOM 结构发生改变的时候,必须重新调用 scroll.refresh() 方法重新计算来确保滚动效果的正常。

2. Vue中的使用

better-scroll可以很好地和Vue配合使用,在异步获取数据和实现动态更新的时候发挥着强大的作用。
使用better-scroll配合Vue实现下拉刷新的示例:

Vue中的template配置

  import BScroll from 'better-scroll'
  export default{
    data(){
      return {
        data: []
      }
    },
    created(){
      this.loadData()
    },
    methods:{
      loadData(){
        requestData().then((res) =>{
          this.data = res.data.concat(this.data)
          this.$nextTick(() => {
            if(!this.scroll){
              this.scroll = new BScroll(this.$refs.wrapper, {})
              this.scroll.on('touchend', (pos) =>{
              // 下拉动作,派发touchend时间监听这个动作
              if(pos.y > 50){
                this.loadData() // 重新请求数据
              }
              })
            }else{
              this.scroll.refresh()
            }
          })
        })
      }
    }
  }

但是以上代码中存在大量的命令式的代码,如果项目中存在着许多类似滚动组件,就会写很多类似的命令式的重复的代码,并且在上面的代码中数据请求和better-scroll之间也是做了强耦合,这样在Vue中并不是很推荐。
因此最好的办法是封装scroll组件,并在全局注册,之后再使用就很方便

使用Js对 better-scroll 做一层 Vue 的封装:通过 props 的形式,把一些对 better-scroll 定制化的控制权交给父组件;通过 methods 暴露的一些方法对 better-scroll 的方法做一层代理;通过 watch 传入的 data,当 data 发生改变的时候,在适当的时机调用 refresh 方法重新计算 better-scroll 确保滚动效果正常,这里之所以要有一个 refreshDelay 的设置是考虑到如果我们对列表操作用到了 transition-group 做动画效果,那么 DOM 的渲染完毕时间就是在动画完成之后。

在全局注册了的Scroll组件之后,我们可以更加简单的使用:

Vue中的template配置

  import BScroll from 'better-scroll'
  export default{
    data(){
      return {
        data: [],
        pulldown: true
      }
    },
    created(){
      this.loadData()
    },
    methods:{
      loadData(){
        requestData().then((res) =>{
          this.data = res.data.concat(this.data)
        })
      }
    }
  }

3. 可能出现的问题

  • better-scroll不能滚动
    A:better-scroll的初始化时机不对,或者是当DOM结构发生变化的时候没有重新的计算better-scroll
  • 手指触摸一下页面会滑动很多
    A:将容器的设置-webkit-overflow-scrolling: touch样式删除掉
  • 需要横向滚动的地方不能滚动
    A:添加evenetPassthrough:'horizontal配置,参考官方文档

Cube-Scroll——cube-ui的Scroll组件

在我们的项目开发中,很多都是基于cube-ui上的组件,简洁、美观、开源。安装:npm install cube-ui -S

Cube-UI的官方文档

cube-ui是滴滴公司的技术团队基于Vue.js实现的精致移动端组件库。虽然组件不是非常的全面,但是足够应对基本的使用场景。

关于Cube-Scroll: 使用说明

Cube-ui上的Scroll实际上就是基于better-scroll进行封装的组件,Scroll支持通过插槽自定义内容和样式,可以更加便捷的配置,关于具体的使用,文档中写的非常详细了,只是举个🌰

Cube-Scroll的用法

Scroll在默认情况下是没有下拉刷新和上拉加载的,因此需要options传递配置项pullDownRefreshpullUpLoad开启相应的功能,由computed计算属性options实现动态监听。开启之后,上下拉时,才会触发相应的动画并派发事件,@监听事件之后实现数据的刷新和加载。

computed:{
  options(){
    return{
      pullDownRefresh: this.pullDownRefreshObj,
      pullUpLoad: this.pullUpLoadObj,
      scrollbar: true
    }
  }
}

针对pullDownRefreshpullUpLoad,都在methods中由我们根据项目功能需求自定义,具体配置见文档。

MScroll ——精致的下拉刷新和上拉加载JS框架

MScroll官方文档
MScroll组件主打精致和好用,其中封装着许多好用的方法,易用性和可重用性强、兼容性强可以多端运行。

相较于前面两个Scroll插件,它的优点很多:

  • 一个界面可多个mescroll
  • 可以自动判断列表有无数据
  • 自动控制翻页,不需要手动判断页码,时间等
  • 可以实现更加平滑缓冲效果,并且一键滚动到顶部或者底部
  • 支持图片的懒加载
  • 数据不满屏自动加载下一页
  • 路由跳转前后可以记录列表的滚动为止

安装:npm install --save mescroll.js
Vue中引用组件:import MescrollVue from 'mescroll.js/mescroll.vue'

使用示例:

Mescroll的用法

  • data: 可以配置许多操作,定义mescroll对象,配置下拉和上拉的页码与页面容量之类…
  • methods:下拉刷新回调downCallback(),上拉加载回调upCallback(),mescroll组件的初始化回调mescrollInit(mescroll)
  • beforeRouteEnter(),beforeRouteLeave():配置顶部按钮或者isBounce时才用写,beforeRouteLeave()是记录列表滚动的位置,隐藏顶部按钮和isBounce的配置,beforeRouteEnter()则是滚到原来的列表位置,恢复顶部按钮和isBounce的配置
    更多的配置可以看其mescroll API文档

相比之下,Mescroll更能够适应多需求的项目的发展,能够更好地增强用户的体验,实现流畅智能的交互。

无论是使用何种插件,在逻辑方面💭

  • 下拉刷新的时候,重新请求data, 如果data发生变化,new_data重新覆盖old_data,否则data不变;
  • 上拉加载的时候,请求新页码下的new_data,添加到本地到data上,扩充content的内容,不必将data全部重新请求。
  • 滑到底部无新数据时,显示提示文字,例如“已经加载完毕”,至于这个判断,在前两个scroll组件中,需要我们手动计算判断data的最大页面数maxPage = Math.floor(data.length/perPageNum) + 1,防止滑动时页码超过最大页码;而在mescroll组件中可以实现自动判断是否已经没有数据了,无须手动配置和计算最大页面,十分便捷

这些组件的都为我们的项目开发带来了许多便利🙌,同时结合组件的方法实现对数据的axios请求也是非常好用的😄~在熟悉使用api的同时,了解组件的源码对于我们开发中遇到的问题也非常有帮助🤘


Author: Casey Lu
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Casey Lu !
评论
 Previous
CSS中的Flex弹性布局和定位 CSS中的Flex弹性布局和定位
在移动端的开发中,为了方便起见,Flex弹性布局成为最常见的布局方式,单纯地使用普通定位以及不能满足我们的设计需要。 一、传统的元素定位 传统布局上,对于元素的定位,我们主要从三方面来设置display、position 和 float,此
2020-03-13
Next 
浅谈Node的两三事 浅谈Node的两三事
大多数情况下,我们所见的Javascript是运行在浏览器中的,而事实上,JS是一门"完整"的语言,浏览器只是提供给了它一个上下文。Node.js实际上也是一种上下文,它允许在后端运行JS代码。 针对Node的总结,cc
2020-03-12
  TOC