Empêcher la ligne de défilement de défiler lors du franchissement d'un bloc
P粉038856725
P粉038856725 2024-03-29 23:23:06
0
1
394

J'ai 3 blocs, le deuxième bloc a une ligne et un cercle roulant. Les cercles défileront avec le défilement principal, et lorsque le défilement s'arrêtera, les cercles resteront collés au point le plus proche, qui est le centre de chaque bloc

Mais j'ai ce problème ici, lorsque le scroll principal traverse le deuxième bloc, les cercles arrêtent de défiler et se comportent incorrectement sur la page

Est-il possible de terminer le script pour que lorsque le parchemin principal se croise block2 时,圆圈将自动坚持最后一个案例并完全停止滚动?当我们返回并穿过 block2, il fonctionne à nouveau

Généralement le problème vient du dernier cas, lorsque le parchemin l'atteint, le cercle ne bouge pas plus loin, peut-être y a-t-il une autre solution que l'option que j'ai suggérée

J'ai besoin que le défilement du block2début à la fin soit fluide et lorsque le défilement s'arrête, le cercle doit coller au centre du boîtier le plus proche

Dans mon exemple, c'est ce qui se passe maintenant, si vous arrêtez de faire défiler, il reste là où il doit être, mais pour moi, il ne défile pas correctement jusqu'à la fin

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

répondre à tous(1)
P粉674876385

Si je comprends bien ta question, je pense que tu peux ajouter la demi-hauteur du dernier boîtier au maxTop calcul comme ceci :

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

De cette façon, la position supérieure maximale du cercle sera au milieu du dernier boîtier. Veuillez vérifier l'extrait de code mis à jour :

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
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal