基于vue2实现上拉加载功能


Posted in Javascript onNovember 28, 2017

本文实例为大家分享了vue2实现上拉加载展示的具体代码,供大家参考,具体内容如下

因为我们项目中,还用了swiper。很多都是滑动切换的,但是又得上拉加载,所以导致,很多UI框架,我们用了,都有不同的bug出现,没办法,最后写了一个。代码如下(这个因为很多地方会用,所以建议放在components/common下面):

<template>
  <div class="loadmore">
    <slot></slot>
    <slot name="bottom">
    </slot>
  </div>
</template>

<style>
  .loadmore{
    width:100%;
  }
</style>

<script>
  export default {
    name: 'loadmore',
    props: {
      maxDistance: {
        type: Number,
        default: 0
      },
      autoFill: {
        type: Boolean,
        default: true
      },
      distanceIndex: {
        type: Number,
        default: 2
      },
      bottomPullText: {
        type: String,
        default: '上拉刷新'
      },
      bottomDropText: {
        type: String,
        default: '释放更新'
      },
      bottomLoadingText: {
        type: String,
        default: '加载中...'
      },
      bottomDistance: {
        type: Number,
        default: 70
      },
      bottomMethod: {
        type: Function
      },
      bottomAllLoaded: {
        type: Boolean,
        default: false
      },
    },
    data() {
      return {
        // 最下面出现的div的位移
        translate: 0,
        // 选择滚动事件的监听对象
        scrollEventTarget: null,
        containerFilled: false,
        bottomText: '',
        // class类名
        bottomDropped: false,
        // 获取监听滚动元素的scrollTop
        bottomReached: false,
        // 滑动的方向  down---向下互动;up---向上滑动
        direction: '',
        startY: 0,
        startScrollTop: 0,
        // 实时的clientY位置
        currentY: 0,
        topStatus: '',
        // 上拉加载的状态  ''   pull: 上拉中
        bottomStatus: '',
      };
    },
    watch: {
      // 改变当前加载在状态
      bottomStatus(val) {
        this.$emit('bottom-status-change', val);
        switch (val) {
          case 'pull':
            this.bottomText = this.bottomPullText;
            break;
          case 'drop':
            this.bottomText = this.bottomDropText;
            break;
          case 'loading':
            this.bottomText = this.bottomLoadingText;
            break;
        }
      }
    },
    methods: {
      onBottomLoaded() {
        this.bottomStatus = 'pull';
        this.bottomDropped = false;
        this.$nextTick(() => {
          if (this.scrollEventTarget === window) {
          document.body.scrollTop += 50;
        } else {
          this.scrollEventTarget.scrollTop += 50;
        }
        this.translate = 0;
      });
        // 注释
        if (!this.bottomAllLoaded && !this.containerFilled) {
          this.fillContainer();
        }
      },

      getScrollEventTarget(element) {
        let currentNode = element;
        while (currentNode && currentNode.tagName !== 'HTML' &&
        currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) {
          let overflowY = document.defaultView.getComputedStyle(currentNode).overflowY;
          if (overflowY === 'scroll' || overflowY === 'auto') {
            return currentNode;
          }
          currentNode = currentNode.parentNode;
        }
        return window;
      },
      // 获取scrollTop
      getScrollTop(element) {
        if (element === window) {
          return Math.max(window.pageYOffset || 0, document.documentElement.scrollTop);
        } else {
          return element.scrollTop;
        }
      },
      bindTouchEvents() {
        this.$el.addEventListener('touchstart', this.handleTouchStart);
        this.$el.addEventListener('touchmove', this.handleTouchMove);
        this.$el.addEventListener('touchend', this.handleTouchEnd);
      },
      init() {
        this.bottomStatus = 'pull';
        // 选择滚动事件的监听对象
        this.scrollEventTarget = this.getScrollEventTarget(this.$el);
        if (typeof this.bottomMethod === 'function') {
          // autoFill 属性的实现  注释
          this.fillContainer();
          // 绑定滑动事件
          this.bindTouchEvents();
        }
      },
      // autoFill 属性的实现  注释
      fillContainer() {
        if (this.autoFill) {
          this.$nextTick(() => {
            if (this.scrollEventTarget === window) {
            this.containerFilled = this.$el.getBoundingClientRect().bottom >=
                document.documentElement.getBoundingClientRect().bottom;
          } else {
            this.containerFilled = this.$el.getBoundingClientRect().bottom >=
                this.scrollEventTarget.getBoundingClientRect().bottom;
          }
          if (!this.containerFilled) {
            this.bottomStatus = 'loading';
            this.bottomMethod();
          }
        });
        }
      },
      // 获取监听滚动元素的scrollTop
      checkBottomReached() {
        if (this.scrollEventTarget === window) {
          return document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight;
        } else {
          // getBoundingClientRect用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。 right是指元素右边界距窗口最左边的距离,bottom是指元素下边界距窗口最上面的距离。
          return this.$el.getBoundingClientRect().bottom <= this.scrollEventTarget.getBoundingClientRect().bottom + 1;
        }
      },
      // ontouchstart 事件
      handleTouchStart(event) {
        // 获取起点的y坐标
        this.startY = event.touches[0].clientY;
        this.startScrollTop = this.getScrollTop(this.scrollEventTarget);
        this.bottomReached = false;
        if (this.bottomStatus !== 'loading') {
          this.bottomStatus = 'pull';
          this.bottomDropped = false;
        }
      },
      // ontouchmove事件
      handleTouchMove(event) {
        if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) {
          // 没有在需要滚动的范围内滚动,不再监听scroll
          return;
        }
        // 实时的clientY位置
        this.currentY = event.touches[0].clientY;
        // distance 移动位置和开始位置的差值    distanceIndex---
        let distance = (this.currentY - this.startY) / this.distanceIndex;
        // 根据 distance 判断滑动的方向 并赋予变量  direction down---向下互动;up---向上滑动
        this.direction = distance > 0 ? 'down' : 'up';
        if (this.direction === 'up') {
          // 获取监听滚动元素的scrollTop
          this.bottomReached = this.bottomReached || this.checkBottomReached();
        }
        if (typeof this.bottomMethod === 'function' && this.direction === 'up' &&
            this.bottomReached && this.bottomStatus !== 'loading' && !this.bottomAllLoaded) {
          // 有加载函数,是向上拉,有滚动距离,不是正在加载ajax,没有加载到最后一页
          event.preventDefault();
          event.stopPropagation();
          if (this.maxDistance > 0) {
            this.translate = Math.abs(distance) <= this.maxDistance
                ? this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance : this.translate;
          } else {
            this.translate = this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance;
          }
          if (this.translate > 0) {
            this.translate = 0;
          }
          this.bottomStatus = -this.translate >= this.bottomDistance ? 'drop' : 'pull';
        }
      },
      // ontouchend事件
      handleTouchEnd() {
        if (this.direction === 'up' && this.bottomReached && this.translate < 0) {
          this.bottomDropped = true;
          this.bottomReached = false;
          if (this.bottomStatus === 'drop') {
            this.translate = '-50';
            this.bottomStatus = 'loading';
            this.bottomMethod();
          } else {
            this.translate = '0';
            this.bottomStatus = 'pull';
          }
        }
        this.direction = '';
      }
    },
    mounted() {
      this.init();
    }
  };
</script>

然后哪个页面需要,在哪个页面导入即可:import LoadMore from './../common/loadmore.vue';在需要引入他的页面写法如下:

<template>
 <section class="finan">
  <!-- 上拉加载更多 -->
  <load-more
  :bottom-method="loadBottom"
  :bottom-all-loaded="allLoaded"
  :bottomPullText='bottomText'
  :auto-fill="false"
  @bottom-status-change="handleBottomChange"
  ref="loadmore">
    <div>
  这里写你需要的另外的模块
    </div>
    <div v-show="loading" slot="bottom" class="loading"> 这个div是为让上拉加载的时候显示一张加载的gif图
     <img src="./../../assets/main/uploading.gif">
    </div>
  </load-more>
 </section>
</template>

然后在此页面的data里和methods设置如下:

export default {
    name: 'FinancialGroup',
    props:{
 
    },
    data () {
      return {
        // 上拉加载数据
        scrollHeight: 0,
        scrollTop: 0,
        containerHeight: 0,
        loading: false,
        allLoaded: false,
        bottomText: '上拉加载更多...',
        bottomStatus: '',
        pageNo: 1,
        totalCount: '',
      }
    },
    methods: {
    /* 下拉加载 */
    _scroll: function(ev) {
      ev = ev || event;
      this.scrollHeight = this.$refs.innerScroll.scrollHeight;
      this.scrollTop = this.$refs.innerScroll.scrollTop;
      this.containerHeight = this.$refs.innerScroll.offsetHeight;
    },
    loadBottom: function() {
      this.loading = true;
      this.pageNo += 1;  // 每次更迭加载的页数
      if (this.pageNo == this.totalGetCount) {
        // 当allLoaded = true时上拉加载停止
        this.loading = false;
        this.allLoaded = true;
      }
      api.commonApi(后台接口,请求参数) 这个api是封装的axios有不懂的可以看vue2+vuex+axios那篇文章
          .then(res => {
        setTimeout(() => {
      要使用的后台返回的数据写在setTimeout里面
         this.$nextTick(() => {
          this.loading = false;
        })
      }, 1000)
     });
    },
    handleBottomChange(status) {
      this.bottomStatus = status;
    },
  }

这样就完成了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript 类、命名空间、代码组织代码
Jul 31 Javascript
window.open不被拦截的实现代码
Aug 22 Javascript
jquery利用命名空间移除绑定事件的方法
Mar 11 Javascript
vue.js表格分页示例
Oct 18 Javascript
AngularJS服务service用法总结
Dec 13 Javascript
Ext JS 实现建议词模糊动态搜索功能
May 13 Javascript
Bootstrap table学习笔记(2) 前后端分页模糊查询
May 18 Javascript
js实现图片轮播效果学习笔记
Jul 26 Javascript
es6 字符串String的扩展(实例讲解)
Aug 03 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
Apr 29 Javascript
Node.js API详解之 repl模块用法实例分析
May 25 Javascript
vue实现在data里引入相对路径
Jun 05 Vue.js
微信小程序模板和模块化用法实例分析
Nov 28 #Javascript
基于Vue的移动端图片裁剪组件功能
Nov 28 #Javascript
javaScript canvas实现(画笔大小 颜色 橡皮的实例)
Nov 28 #Javascript
基于Vue框架vux组件库实现上拉刷新功能
Nov 28 #Javascript
JavaScript中关于class的调用方法
Nov 28 #Javascript
基于vue+canvas的excel-like组件实例详解
Nov 28 #Javascript
JS原型继承四步曲及原型继承图一览
Nov 28 #Javascript
You might like
PHP 页面跳转到另一个页面的多种方法方法总结
2009/07/07 PHP
php生成随机密码自定义函数代码(简单快速)
2014/05/10 PHP
PHP使用get_headers函数判断远程文件是否存在的方法
2014/11/28 PHP
使用PHP实现下载CSS文件中的图片
2015/12/06 PHP
PHP引用的调用方法分析
2016/04/25 PHP
使用laravel的migrate创建数据表的方法
2019/09/30 PHP
两个Javascript小tip资料
2010/11/23 Javascript
jquery load事件(callback/data)使用方法及注意事项
2013/02/06 Javascript
获取offsetTop和offsetLeft值的js代码(兼容)
2013/04/16 Javascript
jQuery内置的AJAX功能和JSON的使用实例
2014/07/27 Javascript
node.js中watch机制详解
2014/11/17 Javascript
jQuery实现分章节锚点“回到顶部”动画特效代码
2015/10/23 Javascript
常用js,css文件统一加载方法(推荐) 并在加载之后调用回调函数
2016/09/23 Javascript
javascript基本数据类型及类型检测常用方法小结
2016/12/14 Javascript
JS实现的自动打字效果示例
2017/03/10 Javascript
详解HTML5 使用video标签实现选择摄像头功能
2017/10/25 Javascript
使用react实现手机号的数据同步显示功能的示例代码
2018/04/03 Javascript
小程序自定义日历效果
2018/12/29 Javascript
node.js微信小程序配置消息推送的实现
2019/02/13 Javascript
JS typeof fn === 'function' &amp;&amp; fn()详解
2020/08/22 Javascript
python实现linux下使用xcopy的方法
2015/06/28 Python
python计算一个序列的平均值的方法
2015/07/11 Python
python+selenium实现自动抢票功能实例代码
2018/11/23 Python
在Python中调用Ping命令,批量IP的方法
2019/01/26 Python
只需7行Python代码玩转微信自动聊天
2019/01/27 Python
python实现最小二乘法线性拟合
2019/07/19 Python
Django框架反向解析操作详解
2019/11/28 Python
为什么相对PHP黑python的更少
2020/06/21 Python
宏碁西班牙官网:Acer西班牙
2021/01/08 全球购物
什么是JNDI的上下文?如何初始化JNDI上下文
2012/03/10 面试题
经济管理专业自荐信
2013/12/30 职场文书
物控部经理职务说明书
2014/02/25 职场文书
门卫岗位职责说明书
2014/08/18 职场文书
自主招生自荐信格式范文
2015/03/25 职场文书
2015年保管员工作总结
2015/04/30 职场文书
中国古代史学名著《战国策》概述
2019/08/09 职场文书