防止越过方块时滚动线滚动
P粉038856725
P粉038856725 2024-03-29 23:23:06
0
1
395

我有 3 个块,第二个块有一条线和一个滚动圆。圆圈会随着主滚动一起滚动,当滚动停止时,圆圈会粘到最近的点,即每个块的中心

但是我在这里遇到这样的问题,当主滚动穿过第二个块时,圆圈停止滚动并且在页面上表现不正确

是否可以完成脚本,以便当主滚动穿过 block2 时,圆圈将自动坚持最后一个案例并完全停止滚动?当我们返回并穿过 block2 时,相应地,它应该再次工作

一般来说,问题在于最后一种情况,当滚动到达它时,圆圈不会进一步移动,也许还有另一种解决方案,而不是我建议的选项

我需要从block2开始到结束的滚动是平滑的,并且当滚动停止时,圆圈应该粘在最近的案例的中心

在我的示例中,这就是现在发生的情况,如果您停止滚动,那么它会停留在需要的位置,但对我来说它不会正确滚动到末尾

const circle = document.querySelector(".circle");
const cases = document.querySelectorAll(".case");
let timer = null;

const detectCase = () => {
  const circleCenter = circle.offsetTop + circle.offsetHeight / 2;
  let activeCase = null,
    minDist = Infinity;
  cases.forEach((elem) => {
    const caseCenter = elem.offsetTop + elem.offsetHeight / 2;
    const dist = Math.abs(caseCenter - circleCenter);
    if (dist < minDist) {
      minDist = dist;
      activeCase = elem;
    }
  });
  return activeCase;
};

const handleScroll = () => {
  const {
    height: blockHeight
  } = document.querySelector(".block2").getBoundingClientRect();
  const maxTop = cases[cases.length - 1].offsetTop;
  const minTop = cases[0].offsetTop;
  let {
    height: startTop
  } = cases[0].getBoundingClientRect();
  let scrollDist = startTop / 2 + window.scrollY;
  scrollDist = scrollDist > maxTop ? maxTop : scrollDist < minTop ? minTop : scrollDist;
  circle.style.top = `${scrollDist}px`;
  circle.style.backgroundSize = `15px ${blockHeight}px`;
  circle.style.backgroundPosition = `0 ${-scrollDist}px`;
  if (timer) return;
  timer = setTimeout(() => {
    const active = detectCase();
    const activePos = active.offsetTop + active.offsetHeight / 2;
    circle.style.top = `${activePos}px`;
    circle.style.backgroundPosition = `0 ${-activePos}px`;
    circle.style.transition = "0.5s";
    timer = null;
  }, 800);
  circle.style.transition = "";
};

const handleWindowSize = () => {
  if (window.innerWidth >= 991) {
    window.addEventListener("scroll", handleScroll);
    window.addEventListener("resize", handleScroll);
  } else {
    window.removeEventListener("scroll", handleScroll);
    window.removeEventListener("resize", handleScroll);
  }
};

handleScroll();
handleWindowSize();
window.addEventListener("resize", handleWindowSize);
.block1 {
  height: 200px;
  background-color: gray;
}

.block3 {
  height: 600px;
  background-color: gray;
}

.block2 {
  height: 100%;
  position: relative;
}

.block2,
.block2 .circle {
  background: linear-gradient(214deg, rgba(79, 142, 255, 0) 0%, #4f8eff 10%, #f5e550 90%, rgba(79, 142, 255, 0) 100%) center/3px calc(100% - 100px) no-repeat;
}

.block2 .circle {
  width: 15px;
  height: 15px;
  left: calc(50% - 8px);
}

.block2 .circle,
.block2 .circle::before {
  position: absolute;
  border-radius: 50%;
}

.block2 .circle::before {
  content: "";
  inset: 3px;
  background-color: white;
}

.text {
  text-align: center;
  padding: 200px 50px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<div class="block1"></div>
<div class="block2">
  <div class="circle"></div>
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 1</div>
      <div class="col-2"></div>
      <div class="col-5 text">Text 1</div>
    </div>
  </div>
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 2</div>
      <div class="col-2"></div>
      <div class="col-5 text">Text 2</div>
    </div>
  </div>
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 3</div>
      <div class="col-2"></div>
      <div class="col-5 text">Text 3</div>
    </div>
  </div>
</div>
<div class="block3"></div>

P粉038856725
P粉038856725

全部回复(1)
P粉674876385

如果我正确理解您的问题,我认为您可以将最后一个案例的半高添加到 maxTop 计算中,如下所示:

let {
    height: lastCaseHeight
  } = cases[cases.length - 1].getBoundingClientRect();
  maxTop = maxTop + (lastCaseHeight / 2)

这样,圆的最大顶部位置将位于最后一个案例的中间。请检查更新的代码片段:

const circle = document.querySelector(".circle");
const cases = document.querySelectorAll(".case");
let timer = null;

const detectCase = () => {
  const circleCenter = circle.offsetTop + circle.offsetHeight / 2;
  let activeCase = null,
    minDist = Infinity;
  cases.forEach((elem) => {
    const caseCenter = elem.offsetTop + elem.offsetHeight / 2;
    const dist = Math.abs(caseCenter - circleCenter);
    if (dist  {
  const {
    height: blockHeight
  } = document.querySelector(".block2").getBoundingClientRect();
  let maxTop = cases[cases.length - 1].offsetTop;
  const minTop = cases[0].offsetTop;
  let {
    height: startTop
  } = cases[0].getBoundingClientRect();
  
  let {
    height: lastCaseHeight
  } = cases[cases.length - 1].getBoundingClientRect();
  maxTop = maxTop + (lastCaseHeight / 2)
  
  let scrollDist = startTop / 2 + window.scrollY;
  scrollDist = scrollDist > maxTop ? maxTop : scrollDist  {
    const active = detectCase();
    const activePos = active.offsetTop + active.offsetHeight / 2;
    circle.style.top = `${activePos}px`;
    circle.style.backgroundPosition = `0 ${-activePos}px`;
    circle.style.transition = "0.5s";
    timer = null;
  }, 800);
  circle.style.transition = "";
};

const handleWindowSize = () => {
  if (window.innerWidth >= 991) {
    window.addEventListener("scroll", handleScroll);
    window.addEventListener("resize", handleScroll);
  } else {
    window.removeEventListener("scroll", handleScroll);
    window.removeEventListener("resize", handleScroll);
  }
};

handleScroll();
handleWindowSize();
window.addEventListener("resize", handleWindowSize);
.block1 {
  height: 200px;
  background-color: gray;
}

.block3 {
  height: 600px;
  background-color: gray;
}

.block2 {
  height: 100%;
  position: relative;
}

.block2,
.block2 .circle {
  background: linear-gradient(214deg, rgba(79, 142, 255, 0) 0%, #4f8eff 10%, #f5e550 90%, rgba(79, 142, 255, 0) 100%) center/3px calc(100% - 100px) no-repeat;
}

.block2 .circle {
  width: 15px;
  height: 15px;
  left: calc(50% - 8px);
}

.block2 .circle,
.block2 .circle::before {
  position: absolute;
  border-radius: 50%;
}

.block2 .circle::before {
  content: "";
  inset: 3px;
  background-color: white;
}

.text {
  text-align: center;
  padding: 200px 50px;
}

Text 1
Text 1
Text 2
Text 2
Text 3
Text 3
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板