列表页面与BackTop平滑滚动

156 阅读2分钟

这次总结一下BackTop组件的使用。

当列表数据较多时,用户很可能因为阅读或查找内容已经将列表上滑至距离顶部很远了,现在想要回到页面顶部进行其它操作。

应该为用户提供一个BackTop,一键到达列表组件顶部。

BackTop通常习惯下是悬浮(固定)在页面的右下角位置,这个可以根据实际情况调整展示的位置。

由于该组件是悬浮展示的,不可避免可能对页面或列表内容有遮挡,所以建议一开始不展示BackTop,只有当用户上滑一定距离后再展示。

个人认为一般情况下滑动高度超出列表滚动容器的高度即可展示BackTop

点击BackTop后需要将列表内容滚动到顶部,推荐使用平滑滚动的方式。

页面滚动方式

scrollTop

container.scrollTop = 0;,设置滚动容器的scrollTop属性为0,可以直接回到顶部。

scrollTo(x, y)

  • x 相当于设置滚动容器的scrollLeft。
  • y 相当于设置滚动容器的scrollTop。

container.scrollTo(0, 0),设置y参数为0,则相当于设置了scrollTop=0

在个别低版本的安卓机(如:oppo r11 plus)上scrollTo有兼容性问题。

scrollTo(options)

  • options是一个对象,可以包含以下参数:
    • top 相当于设置scrollTop

    • left 相当于设置scrollLeft

    • behavior 行为,允许的值:

      说明
      smooth表示平滑滚动并产生过渡效果
      instant表示滚动会直接跳转到目标位置,没有过渡效果。
      auto默认,由浏览器决定是否要产生过渡效果😭

behavior设置为'smooth'目前也存在兼容性问题。

css属性scroll-behavior

想要实现滚动缓动效果,可以给滚动容器设置css属性scroll-behavior: smooth;

由于直接给滚动容器加了该css属性,导致列表页面刷新时高度复位也呈现缓动的效果。

列表页面刷新高度复位是不需要滚动缓动效果的,在滚动前需要先设置scroll-behavior: auto;

或者自己写(抄)一个缓动算法

// 先加速后减速
// @params duration 整个缓动的持续时间
// @params lasted 已持续的时间
// @params startValue 开始值,页面的滚动高度
// @params changeValue 变化值,高度归0,变化值为-startValue
// @return 返回当前变化后的值 即当前页面的滚动高度
function easeInOut(lasted, startValue, changeValue, duration) {
  // 系数:已持续时间 比上 总持续时间的一半
  lasted /= duration / 2;
  // 未过半/前半段(In状态) 系数是逐渐增长的
  if (lasted < 1) {
    // 前半段系数是增长的(0-1之间),变化是指数级别递增的
    return (changeValue / 2) * lasted * lasted + startValue;
  }
  // 进入后半段,系数应该是[1, 2]
  // 减掉1,系数剩下[0, 1]
  lasted--;
  startValue += changeValue / 2;
  // 这里也是以指数级在变化
  return (-changeValue / 2) * (lasted * (lasted - 2)) + startValue;
}

function scrollTopSmoothly(el, duration = 300) {
  const startValue = el.scrollTop;
  const changeValue = -startValue;
  const beginTime = Date.now();
  let lasted = 0;
  
  function scroll() {
    // 已过去的时间
    lasted = Date.now() - beginTime;
    // lasted不能超出duration
    if (lasted > duration) lasted = beginTime;
    el.scrollTop = easeInOut(lasted, startValue, changeValue, duration);
    // 结束
    if (lasted > duration) return;
    requestAnimationFrame(scroll);
  }
  scroll();
}