【前端】原生实现上拉加载和下拉刷新

10/4/2022 JS

# 概述

上拉加载及下拉刷新都依赖于用户交互,关键是要理解在什么场景,什么时机下触发交互动作。
开源解决方案:iscrollbetter-scrollpulltorefresh.js 等第三方库。

  • 上拉加载
  • 下拉刷新
  • 示例 HTML 结构
    <main>
      <p class="refreshText"></p>
      <ul id="refreshContainer">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
        <li>555</li>
        ...
      </ul>
    </main>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

# 上拉加载

  • 基本原理:如何判断页面触底?

    • scrollTop:滚动视窗的高度距离 window 顶部的距离,它会随着往上滚动而不断增加,初始值是 0,它是一个变化的值。
    • clientHeight:一个固定的值,表示屏幕可视区域的高度。
    • scrollHeight:页面不能滚动时也是存在的,此时等于 clientHeight。scrollHeight 表示 body 所有元素的总长度(包括 body 自身的 padding)。
  • 公式表示:scrollTop + clientHeight >= scrollHeight

  • 代码实现:

    let clientHeight = document.documentElement.clientHeight;
    let scrollHeight = document.body.scrollHeight;
    let scrollTop = document.documentElement.scrollTop;
    let distance = 50; //距离视窗还用50的时候,开始触发
    if (scrollTop + clientHeight >= scrollHeight - distance) {
      console.log('开始加载数据');
    }
    
    1
    2
    3
    4
    5
    6
    7

# 下拉刷新

  • 基本原理:页面本身置于顶部时,用户下拉时需要触发的动作。

  • Step1:监听原生 touchstart 事件,记录其初始位置的值,即 e.touches[0].pageY

    var _element = document.getElementById('refreshContainer'),
      _refreshText = document.querySelector('.refreshText'),
      _startPos = 0,
      _transitionHeight = 0;
    
    _element.addEventListener(
      'touchstart',
      function (e) {
        _startPos = e.touches[0].pageY; // 记录初始位置
        _element.style.position = 'relative';
        _element.style.transition = 'transform 0s';
      },
      false
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • Step2:监听原生 touchmove 事件,记录并计算当前滑动的位置值与初始位置值的差值,大于 0 表示向下拉动,并借助 CSS3 的 translateY 属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值。

    _element.addEventListener(
      'touchmove',
      function (e) {
        _transitionHeight = e.touches[0].pageY - _startPos;
        if (_transitionHeight > 0 && _transitionHeight < 60) {
          _refreshText.innerText = '下拉刷新';
          _element.style.transform = 'translateY(' + _transitionHeight + 'px)';
    
          if (_transitionHeight > 55) {
            _refreshText.innerText = '释放更新';
          }
        }
      },
      false
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  • Step3:监听原生 touchend 事件,若此时元素滑动达到最大值,则触发 callback,同时将 translateY 重设为 0,元素回到初始位置。

    _element.addEventListener(
      'touchend',
      function (e) {
        _element.style.transition = 'transform 0.5s ease 1s';
        _element.style.transform = 'translateY(0px)';
        _refreshText.innerText = '更新中...';
        // todo...
      },
      false
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# 参考

Last Updated: 10/8/2022, 2:29:52 PM