0 Like
回到顶部的几种玩法

回到顶部的几种玩法

115 PV0 LikeJavaScript回到顶部WebAPI
前不久优化 FE 的时候用 withRouter 封装了一个 ScrollRestoration 组件,里面用到了 window.scrollTo(0, 0)。而 FE 回到顶部的小猫用的是 requestAnimationFrame,然后去网上搜索一下发现还有其他一些冷门的方法,遂结合 caniuse 和例子总结一番。

scrollTop

在 Chrome 中, 通过 `document.documentElement.scrollTop` 来获取滚动条距离顶端的位置;而在 FF 和 Safari 中,则是通过 `document.body.scrollTop` .

在 Chrome 中,`document.body.scrollTop` 恒为 0, 在 FF 和 Safari 中,`document.documentElement.scrollTop`恒为 0.

因此做兼容的话,可以通过两者相加来获取滚动条距离顶端的位置。

这两个属性可以被设置,所以业界常用的回到顶部的做法如下。

`document.body.scrollTop = document.documentElement.scrollTop = 0


`

最后扩充一个属性 `window.pageYOffset`, 这个属性同样是获取滚动条距离顶端的位置,在 Chrome 和 FF 都可以使用,⚠️ 但是这个属性不能够设置位置,并且在 Safari 上不能用

scrollTo()

用过 React 的同学应该对这个方法不陌生。因为用到了 hashHistory,它是建立在 history 之上的,当路由发生变化时会记住原路由的状态,跳转新页面后默认停留在原页面的位置。 所以我们经常用这个简单方法让页面回到顶部(当然关于 withRouter 是另外一个话题了,详情戳 scroll-restoration)

window.scrollTo() 接收两种参数形式。

第一种是 `window.scrollTo(x-coord, y-coord )`, 其中 `x-coord` 是文档中的横轴坐标, `y-coord` 是文档中的纵轴坐标,所以一般通过 `window.scrollTo(0, 0)` 的方式回到顶部。

window.scrollTo(options)

第二种是 `window.scrollTo(options)`, 接受一个参数对象,其中 top 相当于 y-coord,left 相当于 x-coord,而 behavior 里有个属性值是 ‘smooth’ ,可以平滑的滚动到顶部,很赞。

`window.scrollTo({
    left: 0,
    top: 0,
    behavior: 'smooth' / 'instant' / 'auto'
})


`

在挖一下,还有一个方法是 `window.scroll()`, 它和 `window.scrollTo()` 的用法一模一样。

scrollBy()

这个方法和 `scrollTo()` 的传参形式一样,都是传递 `x-coord, y-coord` 或者 `option`,不同的是, `scrollTo()` 传递的参数是一个对于文档的一个绝对的量,而 `scrollBy()` 传递的是一个相对于自身当前位置的一个量。

因此,可以用下面的方式回到顶部。

`const top = document.body.scrollTop || document.documentElement.scrollTop
scrollBy(0,-top);

`

当然,FF 还有两个方法叫做 `window.scrollByLines(lines)``window.scrollByPages()`, 两种方法在 Chrome 和 Safari 无效,当作了解即可。

其他

当然还看到别人在说在文档头部放一个隐藏的锚点,或者用 `element.scrollIntoView()` 之类的方式,这些就有些反人类了,这里不打算介绍。

番外篇:平滑滚动

这里主要谈一谈 `requestAnimationFrame`,我在 FE 回到顶部的小猫用到了这个 API,一开始是这样写的,但这样有个问题是写死了每次递归只往上走 160px,但如果页面很长的话,这个速度就会很慢。

`   public scrollToTop1 = () => {
    let time: number = 0;
    document.documentElement.scrollTop -= 160;
    if (document.documentElement.scrollTop <= 0) {
      window.cancelAnimationFrame(time);
    } else {
      time = window.requestAnimationFrame(this.scrollToTop);
    }
  };

`

改进版:

`  public scrollToTop = () => {
    let timer: number = 0;
    cancelAnimationFrame(timer);
    const startTime = +new Date();
    const b = document.body.scrollTop || document.documentElement.scrollTop;
    const d = 500;
    const c = b;
    timer = requestAnimationFrame(function func() {
      const t = d - Math.max(0, startTime - +new Date() + d);
      document.documentElement.scrollTop = document.body.scrollTop =
        (t * -c) / d + b;
      timer = requestAnimationFrame(func);
      if (t === d) {
        cancelAnimationFrame(timer);
      }
    });
  };

`
防抖和节流

PREVIOUS POST

防抖和节流

深入理解并手写遵循 Promise/A+ 规范的 Promise

NEXT POST

深入理解并手写遵循 Promise/A+ 规范的 Promise

    Search by