vue loadmore组件上拉加载更多功能示例代码


Posted in Javascript onJuly 19, 2017

最近在做移动端h5页面,所以分页什么的就不能按照传统pc端的分页器的思维去做了,这么小的屏幕去点击也不太方便一般来讲移动端都是上拉加载更多,符合正常使用习惯。

首先简单写一下模板部分的html代码,,很简单清晰的逻辑:

<template>
 <div class="loadmore">
  <div class="loadmore__body">
   <slot></slot>
  </div>
  <div class="loadmore__footer">
   <span v-if="loading">
    <i class="tc-loading"></i>
    <span>正在加载</span>
   </span>
   <span v-else-if="loadable">上拉加载更多</span>
   <span v-else>没有更多了</span>
  </div>
 </div>
</template>

然后就是业务部分了

在动手写组件之前,先理清需求:

加载页面 -> 滑到底部 -> 上拉一定距离 -> 加载第二页 -> 继续前面步骤 -> 没有更多

这是一个用户交互逻辑,而我们需要将其映射为代码逻辑:

首屏自动加载第一页 -> 滑动到底部&&按下时候滑动距离Y轴有一定偏移量 -> 请求后端加载第二页 -> 根据返回字段判断是否还有下一页

有了代码逻辑,主干就出来了,加载和判断由事件来控制,而又作为一个vue组件,我们需要配合vue生命周期来挂载事件和销毁事件

export default {
  mounted() {
    // 确定容器
    // 容器绑定事件
  },
  beforeDestory() {
    // 解绑事件
  },
}

如果没有解绑的话,每次你加载组件,就会绑定一次事件…

然后我们需要一些核心事件回调方法来在合适的时间加载数据渲染页面, 回想一下,第一我们需要http获取数据的load函数,然后我们需要三个绑定事件的回调函数pointDown(), pointMove(), pointUp(),分别对应用户按下、移动、弹起手指操作:

export default {
  ···
  methods:{
   /**
    * 加载一组数据的方法
    */
   load() {
     // 设置options
    this.$axios.request(options).then((res) => {
      // 获取数据后的处理
    }).catch((e) => {
     // 异常处理
    })
   },
    /**
    * 鼠标按下事件处理函数
    * @param {Object} e - 事件对象
    */
   pointerdown(e) {
    // 获取按下的位置
    this.pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY
   },
    /**
    * 鼠标移动事件处理函数
    * @param {Object} e - 事件对象
    */
   pointermove(e) {
    const container = this.$container
    const pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY
    const moveY = pageY - this.pageY
    // 如果已经向下滚动到页面最底部
    if (moveY < 0 && (container.scrollTop + Math.min(
     global.innerHeight,
     container.clientHeight,
    )) >= container.scrollHeight) {
     // 阻止原生的上拉拖动会露出页面底部空白区域的行为(主要针对iOS版微信)
     e.preventDefault()
     // 如果上拉距离超过50像素,则加载下一页
     if (moveY < -50) {
      this.pageY = pageY
      this.load()
     }
    }
   },
    /**
    * 鼠标松开事件处理函数
    */
   pointerup() {
    // 这边就是取消拖动状态,需要注意在拖动过程中不要再次触发一些事件回调,否侧乱套
    this.dragging = false
   },
  },
  ···
}

基本上主干已经算完工了,一些props传入或者一些逻辑控制细节需要再额外添加,贴出整个组件的源码:

<template>
 <div class="loadmore">
  <!-- <div class="loadmore__header"></div> -->
  <div class="loadmore__body">
   <slot></slot>
  </div>
  <div class="loadmore__footer">
   <span v-if="loading">
    <i class="tc-loading"></i>
    <span>正在加载</span>
   </span>
   <span v-else-if="loadable">上拉加载更多</span>
   <span v-else>没有更多了</span>
  </div>
 </div>
</template>
<script type="text/babel">
 import axios from 'axios'
 const CancelToken = axios.CancelToken
 export default {
  data() {
   return {
    /**
     * 总页数(由服务端返回)
     * @type {number}
     */
    count: 0,
    /**
     * 是否正在拖拽中
     * @type {boolean}
     */
    dragging: false,
    /**
     * 已加载次数
     * @type {number}
     */
    times: 0,
    /**
     * 已开始记载
     * @type {boolean}
     */
    started: false,
    /**
     * 正在加载中
     * @type {boolean}
     */
    loading: false,
   }
  },
  props: {
   /**
    * 初始化后自动开始加载数据
    */
   autoload: {
    type: Boolean,
    default: true,
   },
   /**
    * 离组件最近的可滚动父级元素(用于监听事件及获取滚动条位置)
    */
   container: {
    // Selector or Element
    default: 'body',
   },
   /**
    * 禁用组件
    */
   disabled: {
    type: Boolean,
    default: false,
   },
   /**
    * Axios请求参数配置对象
    * {@link https://github.com/mzabriskie/axios#request-config}
    */
   options: {
    type: Object,
    default: null,
   },
   /**
    * 起始页码
    */
   page: {
    type: Number,
    default: 1,
   },
   /**
    * 每页加载数据条数
    */
   rows: {
    type: Number,
    default: 10,
   },
   /**
    * 数据加载请求地址
    */
   url: {
    type: String,
    default: '',
   },
  },
  computed: {
   /**
    * 是否可以加载
    * @returns {boolean} 是与否
    */
   loadable() {
    return !this.disabled && (!this.started || (this.page + this.times) <= this.count)
   },
  },
  mounted() {
   let container = this.container
   if (container) {
    if (typeof container === 'string') {
     container = document.querySelector(container)
    } else if (!container.querySelector) {
     container = document.body
    }
   }
   if (!container) {
    container = document.body
   }
   this.$container = container
   this.onPointerDown = this.pointerdown.bind(this)
   this.onPointerMove = this.pointermove.bind(this)
   this.onPointerUp = this.pointerup.bind(this)
   if (global.PointerEvent) {
    container.addEventListener('pointerdown', this.onPointerDown, false)
    container.addEventListener('pointermove', this.onPointerMove, false)
    container.addEventListener('pointerup', this.onPointerUp, false)
    container.addEventListener('pointercancel', this.onPointerUp, false)
   } else {
    container.addEventListener('touchstart', this.onPointerDown, false)
    container.addEventListener('touchmove', this.onPointerMove, false)
    container.addEventListener('touchend', this.onPointerUp, false)
    container.addEventListener('touchcancel', this.onPointerUp, false)
    container.addEventListener('mousedown', this.onPointerDown, false)
    container.addEventListener('mousemove', this.onPointerMove, false)
    container.addEventListener('mouseup', this.onPointerUp, false)
   }
   if (this.autoload) {
    this.load()
   }
  },
  // eslint-disable-next-line
  beforeDestroy() {
   const container = this.$container
   if (global.PointerEvent) {
    container.removeEventListener('pointerdown', this.onPointerDown, false)
    container.removeEventListener('pointermove', this.onPointerMove, false)
    container.removeEventListener('pointerup', this.onPointerUp, false)
    container.removeEventListener('pointercancel', this.onPointerUp, false)
   } else {
    container.removeEventListener('touchstart', this.onPointerDown, false)
    container.removeEventListener('touchmove', this.onPointerMove, false)
    container.removeEventListener('touchend', this.onPointerUp, false)
    container.removeEventListener('touchcancel', this.onPointerUp, false)
    container.removeEventListener('mousedown', this.onPointerDown, false)
    container.removeEventListener('mousemove', this.onPointerMove, false)
    container.removeEventListener('mouseup', this.onPointerUp, false)
   }
   if (this.loading && this.cancel) {
    this.cancel()
   }
  },
  methods: {
   /**
    * 加载一组数据的方法
    */
   load() {
    if (this.disabled || this.loading) {
     return
    }
    this.started = true
    this.loading = true
    const params = {
     currentPage: this.page + this.times,
     pageSize: this.rows,
    }
    const options = Object.assign({}, this.options, {
     url: this.url,
     cancelToken: new CancelToken((cancel) => {
      this.cancel = cancel
     }),
    })
    if (String(options.method).toUpperCase() === 'POST') {
     options.data = Object.assign({}, options.data, params)
    } else {
     options.params = Object.assign({}, options.params, params)
    }
    this.$axios.request(options).then((res) => {
     const data = res.result
     this.times += 1
     this.loading = false
     this.count = data.pageCount
     this.$emit('success', data.list)
     this.$emit('complete')
    }).catch((e) => {
     this.loading = false
     this.$emit('error', e)
     this.$emit('complete')
    })
   },
   /**
    * 重置加载相关变量
    */
   reset() {
    this.count = 0
    this.times = 0
    this.started = false
    this.loading = false
   },
   /**
    *重新开始加载
    */
   restart() {
    this.reset()
    this.load()
   },
   /**
    * 鼠标按下事件处理函数
    * @param {Object} e - 事件对象
    */
   pointerdown(e) {
    if (this.disabled || !this.loadable || this.loading) {
     return
    }
    this.dragging = true
    this.pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY
   },
   /**
    * 鼠标移动事件处理函数
    * @param {Object} e - 事件对象
    */
   pointermove(e) {
    if (!this.dragging) {
     return
    }
    const container = this.$container
    const pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY
    const moveY = pageY - this.pageY
    // 如果已经向下滚动到页面最底部
    if (moveY < 0 && (container.scrollTop + Math.min(
     global.innerHeight,
     container.clientHeight,
    )) >= container.scrollHeight) {
     // 阻止原生的上拉拖动会露出页面底部空白区域的行为(主要针对iOS版微信)
     e.preventDefault()
     // 如果上拉距离超过50像素,则加载下一页
     if (moveY < -50) {
      this.pageY = pageY
      this.load()
     }
    }
   },
   /**
    * 鼠标松开事件处理函数
    */
   pointerup() {
    this.dragging = false
   },
  },
 }
</script>

以上所述是小编给大家介绍的vue loadmore组件上拉加载更多功能示例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript深入理解js闭包
Jul 03 Javascript
jQuery 全选/反选以及单击行改变背景色实例
Jul 02 Javascript
如何学习Javascript入门指导
Nov 01 Javascript
js实现同一页面多个运动效果的方法
Apr 10 Javascript
理解jquery事件冒泡
Jan 03 Javascript
学习使用grunt来打包JavaScript和CSS程序的教程
Jan 04 Javascript
javascript自定义滚动条实现代码
Apr 20 Javascript
谈谈JavaScript数组常用方法总结
Jan 24 Javascript
node.js实现回调的方法示例
Mar 01 Javascript
IntersectionObserver实现图片懒加载的示例
Sep 29 Javascript
Vue打包后出现一些map文件的解决方法
Feb 13 Javascript
Javascript实现异步编程的过程
Jun 18 Javascript
vue引入swiper插件的使用实例
Jul 19 #Javascript
vue loadmore 组件滑动加载更多源码解析
Jul 19 #Javascript
JS实现的走迷宫小游戏完整实例
Jul 19 #Javascript
JS设置随机出现2个数字的实例代码
Jul 19 #Javascript
利用jQuery异步上传文件的插件用法详解
Jul 19 #jQuery
JavaScript 值类型和引用类型的初次研究(推荐)
Jul 19 #Javascript
基于bootstrap实现多个下拉框同时搜索功能
Jul 19 #Javascript
You might like
为什么《星际争霸》是测试人工智能的理想战场
2019/12/03 星际争霸
thinkphp中AJAX返回ajaxReturn()方法分析
2016/12/06 PHP
Laravel实现autoload方法详解
2017/05/07 PHP
php微信公众号开发之快递查询
2018/10/20 PHP
用Javascript数组处理多个字符串的连接问题
2009/08/20 Javascript
js常用代码段收集
2011/10/28 Javascript
javascript 全选与全取消功能的实现代码
2012/12/23 Javascript
JavaScript AJAX之惰性载入函数
2014/08/27 Javascript
js动态获取子复选项并设计全选及提交的实现方法
2016/06/24 Javascript
Laravel中常见的错误与解决方法小结
2016/08/30 Javascript
Bootstrap基本样式学习笔记之表格(2)
2016/12/07 Javascript
详解如何使用babel进行es6文件的编译
2018/05/29 Javascript
小程序如何定位所在城市及发起周边搜索
2020/02/11 Javascript
JS实现网页烟花动画效果
2020/03/10 Javascript
element-ui和vue表单(对话框)验证提示语(残留)清除操作
2020/09/11 Javascript
vue单元格多列合并的实现
2020/11/26 Vue.js
[03:37]2016完美“圣”典 风云人物:Mikasa专访
2016/12/07 DOTA
[45:59]EG vs OG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
Python 爬虫之超链接 url中含有中文出错及解决办法
2017/08/03 Python
Anaconda下配置python+opencv+contribx的实例讲解
2018/08/06 Python
python3中property使用方法详解
2019/04/23 Python
Python学习笔记之While循环用法分析
2019/08/14 Python
如何基于windows实现python定时爬虫
2020/05/01 Python
Python3通过chmod修改目录或文件权限的方法示例
2020/06/08 Python
浅析Python 条件控制语句
2020/07/15 Python
HTML文本属性&amp;颜色控制属性的实现
2019/12/17 HTML / CSS
一套PHP的笔试题
2013/05/31 面试题
Linux操作面试题
2015/02/11 面试题
大学军训感想
2014/02/12 职场文书
社区道德讲堂实施方案
2014/03/21 职场文书
毕业生面试求职信
2014/06/23 职场文书
运动会演讲稿100字
2014/08/25 职场文书
幼儿园小班教师个人工作总结
2015/02/06 职场文书
餐饮服务员岗位职责
2015/02/09 职场文书
java解析XML详解
2021/07/09 Java/Android
Spring Data JPA框架Repository自定义实现
2022/04/28 Java/Android