带有导航(下一个、上一个)按钮的 CSS 滚动捕捉点
我正在构建一个 carousel,非常简约,使用 CSS捕捉点.拥有 仅 CSS 选项 对我来说很重要,但我可以使用 javascript 进行一些改进(无框架).
I am building a carousel, very minimalist, using CSS snap points. It is important for me to have CSS only options, but I'm fine with enhancing a bit with javascript (no framework).
我正在尝试添加上一个和下一个按钮,以编程方式滚动到下一个或上一个元素.如果 javascript 被禁用,按钮将被隐藏并且轮播仍然有效.
I am trying to add previous and next buttons to scroll programmatically to the next or previous element. If javascript is disabled, buttons will be hidden and carousel still functionnal.
我的问题是关于如何触发滚动到下一个捕捉点?
所有项目都有不同的大小,我发现的大多数解决方案需要像素值(如示例中使用的scrollBy
).scrollBy
40px
适用于第 2 页,但不适用于其他页面,因为它们太大(基于视口的大小).
All items have different size, and most solution I found require pixel value (like scrollBy
used in the exemple). A scrollBy
40px
works for page 2, but not for others since they are too big (size based on viewport).
function goPrecious() {
document.getElementById('container').scrollBy({
top: -40,
behavior: 'smooth'
});
}
function goNext() {
document.getElementById('container').scrollBy({
top: 40,
behavior: 'smooth'
});
}
#container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
border: 2px solid var(--gs0);
border-radius: 8px;
height: 60vh;
}
#container div {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
}
#container div:nth-child(1) {
background: hotpink;
color: white;
height: 50vh;
}
#container div:nth-child(2) {
background: azure;
height: 40vh;
}
#container div:nth-child(3) {
background: blanchedalmond;
height: 60vh;
}
#container div:nth-child(4) {
background: lightcoral;
color: white;
height: 40vh;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<button onClick="goPrecious()">previous</button>
<button onClick="goNext()">next</button>
推荐答案
好问题!我将此视为挑战.
所以,我增加了 JavaScript
让它动态工作.按照我的详细解决方案(最后是完整代码):
Nice question! I took this as a challenge.
So, I increased JavaScript
for it to work dynamically. Follow my detailed solution (in the end the complete code):
首先在.container
中添加position: relative
,因为scroll
和height
需要参考code> 检查 .container
.
First, add position: relative
to the .container
, because it need to be reference for scroll
and height
checkings inside .container
.
然后,我们创建3个全局辅助变量
:
Then, let's create 3 global auxiliary variables
:
1) 将项目滚动位置
(顶部和底部)作为arrays
放入array
.示例:[[0, 125], [125, 280], [280, 360]]
(本例中为 3 项).
3) 一个存储一半 .container height
(以后会有用).
2)另一个存储item index
的scroll
位置
1) One to get items scroll positions
(top and bottom) as arrays
into an array
. Example: [[0, 125], [125, 280], [280, 360]]
(3 items in this case).
3) One that stores half of .container height
(it will be useful later).
2) Another one to store the item index
for scroll
position
var carouselPositions;
var halfContainer;
var currentItem;
现在,一个名为 getCarouselPositions
的 函数
创建了带有项目位置的 array
(存储在 carouselPositions
中)和计算 .container
的一半(存储在 halfContainer
中):
Now, a function
called getCarouselPositions
that creates the array
with items positions (stored in carouselPositions
) and calculates the half of .container
(stored in halfContainer
):
function getCarouselPositions() {
carouselPositions = [];
document.querySelectorAll('#container div').forEach(function(div) {
carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
})
halfContainer = document.querySelector('#container').offsetHeight/2;
}
getCarouselPositions(); // call it once
让我们替换 buttons
上的 functions
.现在,当您单击它们时,将调用相同的 function
,但带有 "next"
或 "previous"
参数:
Let's replace the functions
on buttons
. Now, when you click on them, the same function
will be called, but with "next"
or "previous"
argument:
<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>
这里是关于 goCarousel
function
本身的:
Here is about the goCarousel
function
itself:
首先,它创建2个变量
,分别存储top scroll
位置和bottom scroll
位置.
First, it creates 2 variables
that store top scroll
position and bottom scroll
position of carousel.
然后,有 2 个条件来查看当前轮播位置是在大多数 top
还是大多数 bottom
.
如果它在top
并点击"next" 按钮
,它将转到第二个项目的位置.如果它在bottom
并点击"previous"按钮
,它将转到最后一项之前的上一个.
Then, there are 2 conditionals to see if the current carousel position is on most top
or most bottom
.
If it's on top
and clicked "next" button
, it will go to the second item position. If it's on bottom
and clicked "previous" button
, it will go the previous one before the last item.
如果两个条件都失败,则表示当前项目不是第一个或最后一个.因此,它会检查当前位置
是什么,在循环中使用容器的一半与位置数组
进行计算以查看item代码> 正在显示.然后,它结合
"previous"
或 "next"
检查为 currentItem
变量设置正确的下一个位置.
If both conditionals failed, it means the current item is not the first or the last one. So, it checks to see what is the current position
, calculating using the half of the container in a loop with the array of positions
to see what item
is showing. Then, it combines with "previous"
or "next"
checking to set the correct next position for currentItem
variable.
最后,通过scrollTo
使用currentItem
新值到达正确的位置.
Finally, it goes to the correct position through scrollTo
using currentItem
new value.
下面是完整的代码:
var carouselPositions;
var halfContainer;
var currentItem;
function getCarouselPositions() {
carouselPositions = [];
document.querySelectorAll('#container div').forEach(function(div) {
carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
})
halfContainer = document.querySelector('#container').offsetHeight/2;
}
getCarouselPositions(); // call it once
function goCarousel(direction) {
var currentScrollTop = document.querySelector('#container').scrollTop;
var currentScrollBottom = currentScrollTop + document.querySelector('#container').offsetHeight;
if (currentScrollTop === 0 && direction === 'next') {
currentItem = 1;
} else if (currentScrollBottom === document.querySelector('#container').scrollHeight && direction === 'previous') {
console.log('here')
currentItem = carouselPositions.length - 2;
} else {
var currentMiddlePosition = currentScrollTop + halfContainer;
for (var i = 0; i < carouselPositions.length; i++) {
if (currentMiddlePosition > carouselPositions[i][0] && currentMiddlePosition < carouselPositions[i][1]) {
currentItem = i;
if (direction === 'next') {
currentItem++;
} else if (direction === 'previous') {
currentItem--
}
}
}
}
document.getElementById('container').scrollTo({
top: carouselPositions[currentItem][0],
behavior: 'smooth'
});
}
window.addEventListener('resize', getCarouselPositions);
#container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
border: 2px solid var(--gs0);
border-radius: 8px;
height: 60vh;
position: relative;
}
#container div {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
}
#container div:nth-child(1) {
background: hotpink;
color: white;
height: 50vh;
}
#container div:nth-child(2) {
background: azure;
height: 40vh;
}
#container div:nth-child(3) {
background: blanchedalmond;
height: 60vh;
}
#container div:nth-child(4) {
background: lightcoral;
color: white;
height: 40vh;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>
另一个需要添加的好细节是,如果窗口调整大小,则再次调用 getCarouselPositions
函数:
Another good detail to add is to call getCarouselPositions
function again if the window resizes:
window.addEventListener('resize', getCarouselPositions);
就是这样.
这样做很酷.我希望它能以某种方式提供帮助.
That's it.
That was cool to do. I hope it can help somehow.
相关文章