我们依旧从界面及逻辑两块进行分析

1.界面上,只分成简单的两块,一块是上方的刷新文字,一块是下方的内容,然后将上方提示内容隐藏在屏幕之外,一般由两种方式,一种是上面遮一层,另一种是marginTop:负值将其弄出屏幕外,这里我采用的是第一种,代码也很简单,就随便贴一下

  1. .header{
  2. width: 100%;
  3. height: 1rem;这里的高度应该与刷新文字一样高
  4. position: fixed;
  5. z-index: 100;
  6. }

2.功能实现的重头戏是在逻辑上,主要分成下面几个部分

  • 监听事件
  • 位置计算
  • 控制界面变化
  • 数据更新包
  • 我一个一个进行分析,然后带你们入坑。

实现一个上拉加载,下拉刷新2018-09-07 - 图1

监听事件,这块简单,直接贴代码
  1. //el为下拉的整个节点
  2. //这里为添加监听
  3. this.el.addEventListener('touchstart', this.refreshTouchStart);
  4. this.el.addEventListener('touchmove', this.refreshTouchMove);
  5. this.el.addEventListener('touchend', this.refreshTouchEnd);
  6. //记住在不用的时候要移除监听哦
  7. this.el.removeEventListener('touchstart', this.refreshTouchStart);
  8. this.el.removeEventListener('touchmove', this.refreshTouchMovee);
  9. this.el.removeEventListener('touchend', this.refreshTouchEnd);
  10. //具体的函数,我们直接在位置计算中看

位置计算 我们分下拉刷新,上拉加载两块计算,分析可得

下拉刷新的逻辑 = 当前页面的首项在屏幕中且容器向下滑动的距离大于一定值

上拉加载的逻辑 = 当前页面已滑动到底部

好,我们直接看具体的实现逻辑代码

  1. //代码中包含界面变化和数据更新,仔细看哦
  2. refreshTouchStart(e) {
  3. let touch = e.changedTouches[0];
  4. this.tipText = '下拉刷新';
  5. //下拉提示文字
  6. this.startY = touch.clientY;
  7. //获得当前按下点的纵坐标
  8. }
  9. refreshTouchMove(e) {
  10. this.$store.commit('bottomShowFalse');
  11. //与本逻辑无关,滑动时隐藏底部作用
  12. let touch = e.changedTouches[0];
  13. let _move = touch.clientY - this.startY;
  14. //获得滑动的距离
  15. this.bottomFlag = $('.present-box').offset().top + $('.present-box').height() - document.body.clientHeight <= 40;
  16. //滑动到底部标识
  17. if ($('.present-box').offset().top >= this.headerHeight) {
  18. //内容主体超出了一个头部的距离
  19. if (_move > 0 && _move < 1000) {
  20. //滑动距离>0代表下拉
  21. //<1000是为了防止神人无限拉阿拉
  22. this.el.style.marginTop = _move + 'px';
  23. //根据拉的距离,实现界面上的变化(界面变化)
  24. this.moveDistance = touch.clientY - this.startY;
  25. //记录滑动的距离,在松手后让他滑啊滑滑回去
  26. if (_move > 50) {
  27. //拉到一定程度再下拉刷新,防止误操作
  28. this.tipText = '松开即可刷新'//上面有了
  29. }
  30. }
  31. }
  32. }
  33. refreshTouchEnd() {
  34. this.$store.commit('bottomShowTrue');
  35. //松开后底部就biu的出现啦
  36. if (this.bottomFlag) {
  37. //若符合上拉加载的条件,则直接进行数据更新
  38. this.$emit('loadBottom');
  39. }
  40. let that = this;
  41. if (this.moveDistance > 50) {
  42. //拉了一定距离才触发加载动作
  43. this.tipText = '数据加载中...';
  44. let timer = setInterval(function () {
  45. that.el.style.marginTop = that.el.style.marginTop.split('px')[0] - 5 + 'px';
  46. //如果拉的很长,一次性弹回去影响用户体验,所以先让他弹到50的高度,然后再进行数据更新
  47. if (Number(that.el.style.marginTop.split('px')[0]) <= 50) {
  48. //小于50后就不进行界面变化了,先进行数据更新再变化
  49. clearInterval(timer);
  50. new Promise((resolve, reject) => {
  51. that.$emit('loadTop', resolve, reject);
  52. //通知父控件,下拉刷新条件满足了,你更新吧
  53. }).then(() => {
  54. that.resetBox();
  55. }).catch(() => {
  56. that.resetBox();
  57. //界面恢复(也就是弹回去啦)
  58. });
  59. }
  60. }, 1);
  61. //通过一个promise,让数据更新结束后再进行界面变化。也可以采用其他的方式,如async await方式
  62. } else {
  63. this.resetBox();
  64. }
  65. }
  66. resetBox() {
  67. let that = this;
  68. //使用定时器的方式,biubiubiu的实现滑动界面刷新的效果。
  69. if (this.moveDistance > 0) {
  70. let timer = setInterval(function () {
  71. that.el.style.marginTop = that.el.style.marginTop.split('px')[0] - 1 + 'px';
  72. if (Number(that.el.style.marginTop.split('px')[0]) <= 0) {
  73. clearInterval(timer);
  74. //这里很重要,不删除,可能看到奇奇怪怪的东西哦
  75. }
  76. }, 1)
  77. }
  78. this.moveDistance = 0;
  79. }

效果图

实现一个上拉加载,下拉刷新2018-09-07 - 图2