带有导航(下一个、上一个)按钮的 CSS 滚动捕捉点 [英] CSS Scroll Snap Points with navigation (next, previous) buttons

查看:16
本文介绍了带有导航(下一个、上一个)按钮的 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,因为scrollheight需要参考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 indexscroll位置

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.

这篇关于带有导航(下一个、上一个)按钮的 CSS 滚动捕捉点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆