为scrollTo添加平滑滚动降级方案

Element.scrollTo 是一个dom元素上的方法,可以将元素滚动到指定的坐标位置,使用方法如下:

element.scrollTo(x-coord, y-coord)
element.scrollTo(options)

参数说明:

  • x-coord 是期望滚动到位置水平轴上距元素左上角的像素。
  • y-coord 是期望滚动到位置竖直轴上距元素左上角的像素。
  • options 是一个ScrollToOptions对象。

1、原生API实现方式

我们可以使用 options 参数去让滚动平滑,代码可以如下实现:

el.scrollTo({
  left: 100,
  top: 0,
  behavior: 'smooth'
})

behavior属性在有些浏览器上不支持,不限于有些app修改过的webview等,我们就需要一个降级方案,可以使用浏览器的新的API实现。

2、requestAnimationFrame

2.1、实现方式

如果是静态页面的话,js的动画好像要稍微流畅一点;并且可以控制滚动的速度;
下面的实现仅仅是在x轴上实现的,如果需要在y轴实现,只需要将滚动参数修改一下;
实例:x轴实现的实例如顶部的tab定位等,需求是顶部的tab可以左右滑动,点击tab后底部的卡片会滑动到对应的位置,滑动底部的卡片,顶部的tab也会激活并居中,这就需要实现顶部的平滑滚动;

image.png

requestAnimationFrame 是一个新兴的API,专门为执行动画而生,这个方法每秒会执行60次,其实这个60并不是固定值,和刷新率有关系;

/**
 * 使用动画滚动导航部分
 * @param el {Element} 需要滚动的元素
 * @param start {Number} 滚动开始的位置
 * @param end {Number} 滚动结束的位置
 * @param step {Number} 每一步滚动的长度
 */
export const scrollAnimation = (el, start, end, step) => {
  // 向右滑动的逻辑
  if (start < end) {
    start = start + step;
    // 要是剩下的不够一步就直接撑满,防止页面出现滚动偏移错误
    if (start > end) {
      start = end;
    }
  }
  // 向左滑动的逻辑
  if (start > end) {
    start = start - step;
    if (start < end) {
      start = end;
    }
  }

  el.scrollTo(start, 0);

  // 要是开始和结束是一样的就不会安排下一次的滚动了
  // 在高刷新的屏幕上会有运行的比较块
  if (start !== end) {
    requestAnimationFrame(() => {
      scrollAnimation(el, start, end, step);
    })
  }
};

2.2、使用说明

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘(浏览器重绘通常是60次每秒,回调函数执行次数通常与浏览器屏幕刷新次数相匹配)之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行;

优点:

  • 为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。
  • 可以用个调用requestAnimationFrame返回的一个数字取消执行:cancelAnimationFrame(num);

在高刷新屏幕上运行更快的问题解决(可以通过传进来的参数处理)

3、参考文档

留下回复