Skip to content

滚动到指定位置

原生 js 和 lenis

点击后滚动到页面指定的 id

原生

方法

js
const smoothScrollTo = (element) => {
  // 获取目标元素的当前位置
  const targetPosition =
    element.getBoundingClientRect().top + window.pageYOffset;

  // 获取当前滚动位置
  let currentPosition = window.pageYOffset;

  // 计算滚动距离
  const distance = targetPosition - currentPosition;

  // 定义动画的起始时间
  let startTime = null;

  function animation(currentTime) {
    // 如果是第一次执行,记录起始时间
    if (startTime === null) startTime = currentTime;

    // 计算已经过去的时间
    const timeElapsed = currentTime - startTime;

    // 使用 ease-in-out 动画效果
    const run = ease(timeElapsed, currentPosition, distance, 1000);

    // 更新当前滚动位置
    window.scrollTo(0, run);

    // 如果动画未完成,继续动画
    if (timeElapsed < 1000) requestAnimationFrame(animation);
  }

  // 定义 ease-in-out 动画效果的函数
  function ease(t, b, c, d) {
    t /= d / 2;
    if (t < 1) return (c / 2) * t * t + b;
    t--;
    return (-c / 2) * (t * (t - 2) - 1) + b;
  }
  // 开始动画
  requestAnimationFrame(animation);
};

使用

  • 传入 id 即可 不要加#
js
const scrollgointoview = (id) => {
  // 使用示例
  const targetElement = document.getElementById(id);
  smoothScrollTo(targetElement);
};

lenis

要是使用 项目里面就都使用,否则就不要用

安装

js
npm i lenis -S
  • 或者使用 script 引入
html
<script src="https://unpkg.com/lenis@1.3.4/dist/lenis.min.js"></script>

基础使用

(1) 构造

设置页面平滑滚动

js
const lenis = new Lenis({
  // 容器
  wrapper: window,
  smoothWheel: true,
  // 持续时间 单位秒
  duration: 1.2,
  // 滑动效果的缓动函数
  easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
  // 滑动方向 horizontal 水平方向  vertical 垂直方向
  orientation: "vertical",
  // 滑动手势 horizontal 水平方向  vertical 垂直方向 手机端
  gestureOrientation: "vertical",
  // 页面改变 他也改变
  autoResize: true,
});

const raf = (time) => {
  lenis.raf(time);
  requestAnimationFrame(raf);
};
requestAnimationFrame(raf);

(2) 监听

  • 监听滚动事件和距离
js
lenis.on("scroll", ({ scroll, limit, velocity, direction, progress }) => {
  console.log("scroll", scroll);
  console.log("limit", limit);
  console.log("velocity", velocity);
  console.log("direction 当前的滑动方向", direction);
  console.log("progress 当前的滚动条进度", progress);
});

(3)页面是否能滚动

js
// 停止
lenis.stop();
// 2s开始
setTimeout(() => {
  lenis.start();
}, 2000);

(4)滚动到指定位置

js
const scrollgointoview = (id) => {
  lenis.scrollTo(document.getElementById(id), {
    // 这样页面没有滑动完 不会有任何操作
    lock: true,
    // 偏移
    offset: -50,
    // 滚动到指定元素时,是否触发动画 true 就是不会触发动画
    immediate: false,
    // 动画持续时间
    duration: 1.2,
    // 动画结束后的回调函数
    onComplete: () => {
      console.log("滚动结束");
    },
    // 滑动效果的缓动函数
    easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
  });
};

完整版案例

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://unpkg.com/lenis@1.3.4/dist/lenis.min.js"></script>
  </head>
  <body>
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
    <div id="div4"></div>

    <div class="fixedright">
      <div id="div5" onClick="scrollgointoview('div1')"></div>
      <div id="div6" onClick="scrollgointoview('div2')"></div>
      <div id="div7" onClick="scrollgointoview('div3')"></div>
      <div id="div8" onClick="scrollgointoview('div4')"></div>
    </div>
  </body>
  <script>
    const lenis = new Lenis({
      // 容器
      wrapper: window,
      // 滚轮
      smoothWheel: true,
      // 持续时间 单位秒
      duration: 1.2,
      // 滑动效果的缓动函数
      easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      // 滑动方向 horizontal 水平方向  vertical 垂直方向
      orientation: "vertical",
      // 滑动手势 horizontal 水平方向  vertical 垂直方向 手机端
      gestureOrientation: "vertical",
      // 页面改变 他也改变
      autoResize: true,
    });

    const raf = (time) => {
      lenis.raf(time);
      requestAnimationFrame(raf);
    };
    requestAnimationFrame(raf);

    // 监听
    lenis.on("scroll", ({ scroll, limit, velocity, direction, progress }) => {
      console.log("scroll", scroll);
      console.log("limit", limit);
      console.log("velocity", velocity);
      console.log("direction 当前的滑动方向", direction);
      console.log("progress 当前的滚动条进度", progress);
    });
    // 设置页面是否能滚动
    // lenis.isStopped = true;
    // lenis.stop();
    // setTimeout(() => {
    //   lenis.start();
    // }, 2000);
    const scrollgointoview = (id) => {
      lenis.scrollTo(document.getElementById(id), {
        // 这样页面没有滑动完 不会有任何操作
        lock: true,
        // 偏移
        offset: -50,
        // 滚动到指定元素时,是否触发动画 true 就是不会触发动画
        immediate: false,
        // 动画持续时间
        duration: 1.2,
        // 动画结束后的回调函数
        onComplete: () => {
          console.log("滚动结束");
        },
        // 滑动效果的缓动函数
        easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      });
    };
  </script>
  <style>
    * {
      margin: 0px;
      padding: 0px;
    }
    .fixedright {
      position: fixed;
      width: 100px;
      height: 200px;
      right: 20px;
      top: 50%;
      transform: translateY(-50%);
    }
    #div5 {
      width: 100%;
      height: 50px;
      cursor: pointer;
      background: red;
    }
    #div6 {
      width: 100%;
      height: 50px;
      cursor: pointer;
      background: blue;
    }
    #div7 {
      width: 100%;
      height: 50px;
      cursor: pointer;
      background: yellow;
    }
    #div8 {
      width: 100%;
      height: 50px;
      cursor: pointer;
      background: green;
    }
    #div1 {
      width: 100%;
      height: 1000px;
      background-color: red;
    }
    #div2 {
      width: 100%;
      height: 1000px;
      background-color: blue;
    }
    #div3 {
      width: 100%;
      height: 1000px;
      background-color: yellow;
    }
    #div4 {
      width: 100%;
      height: 1000px;
      background-color: green;
    }
  </style>
</html>