置顶(回到顶部)功能

604 阅读1分钟

手动实现,原生“回到顶部”的功能,不使用插件,可以减少加载外部无用的功能加载。

  • 使用visibility去控制显示。使用display:none隐藏 DOM 元素,会同时导致重排和重绘;使用visibility:hidden只会造成重绘,因为没有布局和位置的改变,所以不发生重排,对页面性能开销比较小
  scroll() {
    const targetEle = document.querySelector(".backtop[css-backtop]");
    if (document.documentElement.scrollTop >= 200) {
      targetEle.style.visibility = "visible";
    } else {
      targetEle.style.visibility = "hidden";
    }
  }
  • throttle节流函数,避免一定时间内重复触发
throttle(fn, wait) {
    let inThrottle, lastFn, lastTime;
    return function () {
      const context = this,
        args = arguments;
      if (!inThrottle) {
        fn.apply(context, args);
        lastTime = Date.now();
        inThrottle = true;
      } else {
        clearTimeout(lastFn);
        lastFn = setTimeout(function () {
          if (Date.now() - lastTime >= wait) {
            fn.apply(context, args);
            lastTime = Date.now();
          }
        }, Math.max(wait - (Date.now() - lastTime), 0));
      }
    };
  }
  • requestAnimationFramesetTimeout去实现一个重复向上滚动的过程,而不是一次性滚到顶部
scrollToTop() {
    const el = document.documentElement;
    const beginTime = Date.now();
    const beginValue = el.scrollTop;
    const rAF =
      window.requestAnimationFrame || ((func) => setTimeout(func, 16));
    const cubic = (value) => Math.pow(value, 3);
    const easeInOutCubic = (value) =>
      value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2;
    const frameFunc = () => {
      const progress = (Date.now() - beginTime) / 500;
      if (progress < 1) {
        el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
        rAF(frameFunc);
      } else {
        el.scrollTop = 0;
      }
    };
    rAF(frameFunc);
  },
  • 设置对应点击和滚动事件,最终调用如下方法
  loadBacktop() {
    const targetEle = document.querySelector(".backtop[css-backtop]");
    targetEle.addEventListener("click", backtopObj.scrollToTop);
    const throttledScrollHandler = util.throttle(backtopObj.scroll, 300);
    window.addEventListener("scroll", throttledScrollHandler);
  },
  • 页面样式设置
<div class="backtop" css-backtop="" style="visibility:hidden"><img data-v-09f6b925=""

        src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAtCAYAAADV2ImkAAAAAXNSR0IArs4c6QAAA3NJREFUaEPtmUvIVVUUx3//QgdJ+KKRgoFFiIIPciSKmCkEaha+EsRHE0HUkMRIsVTEF2pJgQ8CwUdvVBz4QEWEUHxMxIkYRTTSgdLAicpf9sf55H733nP2Puc7OOmu2eX811q/vc7a+6zNFTWa7SnAWmA88AjYL2lHjSlQXcFszwBOtYm3S9LndeWpBdj2GOAG8GoO2F5Jn9UB3Wtg20uAHxJgdktak6ArlPQK2PYGYFMJiC2Sgk9lqwxsez2wuULmrZK+rODX5VIJ2PZG4KuqSYOvpK+r+JcGLtGzMZ6Nksq0U/kK254KnI+RlHi+TdIXJfTpLWF7OfB9meCJ2lI9ndQStlcBexMBqsiS2yMKbHsZcKgKRUmfTZLCZq5+DtteDeyJBanx+VpJO4vi5VbY9mzg9wSYP4ETQN5XzMA3wAhgekK8NZJ25+naAtseC9xKCP4f8BbwOhDA82yUpDu2LwGTE+LmVroFOBsRfwYGRwI/BSZKump7DhB88myhpGO2+2YLG5oAvUrSt826HsC2FwGHE4I9A96TdDlobX8M/FrgN0dS13Pbw4F7CTmCZIWk7xq1L4BtLwSOJAaaJOlKt9b2R8BvBb5zJf3SoJ8InAQGJuRbKWlft64L2PasbOMk+DNV0oVGYQLwfEk/NfmMAq4BryUkXSyp683L9hDgH+CViONjYGYzbLbgWIVftEQT9GjgOtAnATq04MUAfBaYFnF4km2wUJEWS6hwW+Bsse8DR4E3Igx3Jb0TgMM5GbNpknKHnoRNN09S7iliO5zRtwuuWIHvsaR+Afh+ZHUzJJ0uWlFChQuBs0qPA24W5HkqqU8ADkNNGG7aWTRRlix2DrdsupzW+jAbsoa1eb5d0roAPAA4AISk3fYQWCopfHKjZns+cLxAmAScLb5/thHfboi3T9LK8LvxHB4JfJJ9ic5J+jdKmglszwN+rAM4gx4EfJDxPZB0pjt2dLxMga4buChnBzinOsk9HHuj/9sKx6a1pOMxVt0ep0SKOE/T2y9dmdx1tUSnwnlV71Q4pzKdTVdmo7ZoO6dEQfnq2nRzgR6XzKacs1NH1dirflnAsyS1+0ssxtfyvC7gBcCxuubhlzFevgn8VZDoXUlF97XkStdS4eyWcBD4tE3mPyRNSCaKCOsEDhfHv9vkGy8p/Etaiz0HnJdhPQFhR0AAAAAASUVORK5CYII="

        width="22px" height="23px" alt=""></div>

<style>
    .backtop[css-backtop] {
        background-color: rgba(0, 0, 0, .5);
        right: 10px;
        bottom: 100px;
        position: fixed;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        color: #409eff;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 20px;
        box-shadow: 0 0 6px rgb(0 0 0 / 12%);
        cursor: pointer;
        z-index: 5;
    }
</style>
  • 最终实现效果

image.png