Verhindern Sie das Scrollen der Bildlaufzeile beim Überqueren eines Blocks
P粉038856725
P粉038856725 2024-03-29 23:23:06
0
1
381

Ich habe 3 Blöcke, der zweite Block hat eine Linie und einen Rollkreis. Die Kreise scrollen mit dem Hauptscroll, und wenn das Scrollen stoppt, bleiben die Kreise am nächstgelegenen Punkt hängen, der die Mitte jedes Blocks ist

Aber ich habe hier dieses Problem: Wenn der Hauptscroll den zweiten Block kreuzt, hören die Kreise auf zu scrollen und verhalten sich auf der Seite falsch

Ist es möglich, das Skript so zu vervollständigen, dass es beim Kreuzen der Hauptrolle block2 时,圆圈将自动坚持最后一个案例并完全停止滚动?当我们返回并穿过 block2 entsprechend wieder funktionieren sollte

Im Allgemeinen liegt das Problem im letzten Fall: Wenn die Schriftrolle ihn erreicht, bewegt sich der Kreis nicht weiter. Vielleicht gibt es eine andere Lösung als die von mir vorgeschlagene Option

Ich möchte, dass das Scrollen von block2Anfang bis Ende reibungslos verläuft, und wenn das Scrollen stoppt, sollte der Kreis in der Mitte des nächstgelegenen Gehäuses bleiben

In meinem Beispiel passiert jetzt Folgendes: Wenn Sie mit dem Scrollen aufhören, bleibt es dort, wo es sein muss, aber bei mir scrollt es nicht richtig bis zum Ende

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

Antworte allen(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
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage