vue手动实现移动端下拉刷新上滑加载更多

先上代码

<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8' />
  <title>mobile分页</title>
  <script src='https://unpkg.com/vue/dist/vue.js'></script>
  <style>
      html {
          font-size: 40px;
      }

      * {
          margin: 0;
          padding: 0;
      }

      .box {
          overflow: hidden;
          position: relative;
          width: 100%;
          height: 100vh;
          display: flex;
      }

      .navBox {
          overflow-y: auto;
          width: 20%;
          border-right: 1px solid #ddd;
          height: 100%;
      }

      .nav_item {
          padding: 20px 0;
          text-align: center;

      }

      .item_box {
          position: absolute;
          top: 0;
          right: 0;
          overflow-y: auto;
          width: 80%;
          height: 100%;
      }

      .item {
          width: 100%;
          height: 350px;
      }

      .item:nth-child(1n) {
          background: yellow;
      }

      .item:nth-child(2n) {
          background: #13c2c2;
      }

      .item:nth-child(3n) {
          background: #159b76;
      }

      .item:nth-child(4n) {
          background: orange;
      }

      .loadingBox {
          padding: 20px;
          text-align: center;
      }
  </style>
</head>
<body>
<div id='app'>
  <div class='box'>
    <div class='navBox'>
      <div class='nav_item' v-for='(item,index) in navList' :key='index'>{{item.name}}</div>
    </div>
    <div class='item_box'  :style="{'transition':`all .${number}s`,'top':`${translateY}px`}" ref='scroll' id='box' @touchend='touchend' @touchmove='touchmove' @touchstart='touchstart'>
      <div class='loadingBox' v-if='touchstartTitleShow'>释放可刷新...</div>
      <div class='loadingBox' v-if='touchEndTitleShow'>加载中...</div>
      <div class='item' v-for='(itme,index) in list' :key='index'>
        {{index}}
      </div>
      <div class='loadingBox' v-if='loading'>加载中...</div>
      <div class='loadingBox' v-if='!loading&&!hasNext'>已加载全部内容</div>
    </div>
  </div>
</div>
<script type='text/javascript'>
  new Vue({
    el: '#app',
    data: {
      touchEndTitleShow:false, //控制手指离开屏幕的title显示
      touchstartTitleShow:false,//控制手指按下屏幕的title显示
      number:0,//列表回弹动画时间
      translateY:0,//列表随手指下拉而偏移的量
      startY:0,//手指按住的位置的y坐标,也就是起始坐标
      hasNext: true,//是否还有下一页
      loading: false,//loading显示
      navList: [
        {
          name: '分类1'
        },
        {
          name: '分类2'
        },
        {
          name: '分类3'
        },
        {
          name: '分类4'
        },
        {
          name: '分类5'
        },
        {
          name: '分类6'
        }
      ],
      list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    },
    mounted() {
      this.initScrollChange()
    },
    methods: {
      //手指触碰到屏幕
      touchstart(e) {
        this.number = 0
        let y = e.targetTouches[0].pageY
        this.startY = y
      },
      //手指开始滑动
      touchmove(e) {
        let y = e.targetTouches[0].pageY
        if((y>this.startY)&&this.$refs.scroll.scrollTop==0){
          this.touchstartTitleShow = true
          //如果当前移动距离大于初始点击坐标,则视为是下拉。并且要处于顶部才刷新,不能影响正常的列表滑动。
          this.translateY = (y-this.startY)/2
        }
      },
      //手指松开
      touchend(e){
        let y = e.changedTouches[0].pageY
       if(y>this.startY){
         this.number = 4
         this.translateY = 0
         this.touchstartTitleShow = false
         this.touchEndTitleShow = true
         setTimeout(()=>{
           this.touchEndTitleShow = false
         },1000)
         this.startY = 0
       }
      },
      initScrollChange() {
        this.$refs.scroll.onscroll = (e) => {
          const offsetHeight = this.$refs.scroll.offsetHeight //可视区域的高度
          const scrollHeight = this.$refs.scroll.scrollHeight //元素全部高度
          const scrollTop = this.$refs.scroll.scrollTop //滚动条滚动距离
          //可视区域高度加上滚动条滚动距离大于等于元素全部高度则表示滚动到底
          if ((offsetHeight + scrollTop) - scrollHeight >= -1) {
            console.log('到底啦')
            if (!this.loading && this.hasNext) {
              this.getData()
            }
          }
        }
      },
      getData() {
        this.loading = true
        setTimeout(() => {
          for (let i = 0; i < 10; i++) {
            this.list.push(this.list.length + 1)
          }
          this.loading = false
          if (this.list.length > 30) {
            this.hasNext = false
          }
        }, 1000)
      }
    }
  })
</script>
</body>
</html>

效果图


image.png

demo里实现的是左右分布的列表,上下分布的代码一致,改一下布局即可

代码解析:
首先实现加载更多,这个比较容易。要实现此功能,我们就必须得知道我们的元素的滚动条什么时候滚到底部了,只有滚到底部我们才去拉下一页数据

vue里提供了ref来帮助我们获取元素,元素身上有个onscroll 方法,此方法可监听滚动条的滚动

  this.$refs.scroll.onscroll = (e) => {
          const offsetHeight = this.$refs.scroll.offsetHeight     可视区域的高度
          const scrollHeight = this.$refs.scroll.scrollHeight     元素全部高度
          const scrollTop = this.$refs.scroll.scrollTop           滚动条滚动距离

         可视区域高度加上滚动条滚动距离大于等于元素全部高度则表示滚动到底

          if ((offsetHeight + scrollTop) - scrollHeight >= -1) {
            console.log('到底啦')
在这里我们就可以去加载下一页了,但是并不是无脑加载。是有条件的,
只有当loading为false的时候并且有下一页,我们才去加载。以免出现用户一直下滑,我们的程序反复的出现loading
            if (!this.loading && this.hasNext) {
              this.getData()
            }
          }
        }

getData函数这里就不过多描述了

这样一个简单的上滑加载更多就实现了。

现在来解析一下下拉刷新

首先上拉刷新,那我们肯定是要监听用户的手触碰屏幕的事件的。
这里vue也提供了以下事件


image.png

在手指刚触碰到屏幕的时候,我们需要记录下当前的y坐标,以便后续用来作比较分变出此时是上滑还是下拉

在移动的函数里去比较其实坐标和当前坐标的大小,如果是下拉。则动态的修改整个list盒子的top值。

手指松开后就是重置一些东西,但是这里要注意。用户下滑的时候也是会触发这些事件的,所以在松开的函数里,也需要做一个判断,如果是上滑后松开那就不做任何处理,如果是下拉后松开,那就重置一些东西。

具体的实现也不难,上述demo只是一个精简版,但整体思路就是这样。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容