英文:
stop the scroll line from scrolling if the block is crossed
问题
我有3个块,第二个块上有一条线和一个滚动的圆圈。圆圈会随着主滚动一起滚动,当滚动停止时,圆圈会停在最近的点,即每个块的中心。
但我在这里遇到了一个问题,当主滚动穿过第二个块时,圆圈停止滚动,页面上的行为不正确。
是否可能完成脚本,以便当主滚动穿过block2
时,圆圈会自动粘附到最后的位置并停止滚动?当我们再次上升并穿过block2
时,它应该再次正常工作。
总之,问题出在最后一个情况,当滚动到达它时,圆圈不再移动,也许有另一种修复它的选项,而不是我提出的这种。
我希望滚动从block2
的开头到结尾都是平滑的,当滚动停止时,圆圈应该粘附到最近情况的中心。
在我的示例中,现在的情况是,如果停止滚动,它会停在需要停止的地方,但对我来说它不会正确滚动到结尾。
英文:
I have 3 blocks, the second block has a line and a scrolling circle. The circle will scroll along with the main scroll, and when the scroll stops, the circle sticks to the nearest point, which is in the center of each block
But I have such a problem here, when the main scroll crosses the second block, the circle stops scrolling and behaves incorrectly on the page
Is it possible to complete the script so that when the main scroll crosses block2
, the circle will automatically stick to the last case and stop scrolling at all? And when we rise back and cross block2
, then, accordingly, it should work again
In general, the problem is with the last case, when the scroll reaches it, the circle does not move further, maybe there is another option how to fix it, and not the one I suggested
I need the scroll to be smooth from the beginning of block2
to the end, and when the scroll stops, the circle should stick to the center of the nearest case
In my example, this is what happens now, if you stop scrolling, then it sticks where it needs to, but it doesn’t scroll correctly to the end for me
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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);
<!-- language: lang-css -->
.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;
}
<!-- language: lang-html -->
<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>
<!-- end snippet -->
答案1
得分: 1
如果我理解你的问题正确的话,我认为你可以将最后一个案例的一半高度添加到maxTop
的计算中,像这样:
let {
height: lastCaseHeight
} = cases[cases.length - 1].getBoundingClientRect();
maxTop = maxTop + (lastCaseHeight / 2)
这样,圆圈的最大顶部位置将位于最后一个案例的中间。请检查更新后的代码片段:
英文:
If i'm understanding your problem correctly, I think you could just add the half height of the last case to the maxTop
calculation like this:
let {
height: lastCaseHeight
} = cases[cases.length - 1].getBoundingClientRect();
maxTop = maxTop + (lastCaseHeight / 2)
This way the maximum top position for the circle will be at the middle of the last case. Please check the updated snippet:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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();
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 < 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);
<!-- language: lang-css -->
.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;
}
<!-- language: lang-html -->
<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>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论