【问题标题】:Indicators (dots) with CSS scroll snap带有 CSS 滚动捕捉的指示器(点)
【发布时间】:2018-11-17 20:42:21
【问题描述】:

我正在使用 CSS scroll snap 构建一个滚动轮播。

.carousel {
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  width: 100vw;
  white-space: nowrap;
  overflow-x: scroll;
}

.carousel > * {
  display: inline-block;
  scroll-snap-align: start;
  width: 100vw;
  height: 100vh;
}

#x {
  background-color: pink;
}
#y {
  background-color: lightcyan;
}
#z {
  background-color: lightgray;
}
<div class="carousel">
<div id="x">x</div>
<div id="y">y</div>
<div id="z">z</div>
</div>

效果很好;如果您使用触控板或手指滚动轮播,它会吸附到每个项目。

我想补充的是“指标”。例如在 Bootstrap 中,这些是小点或线,表示轮播中有多个内容,轮播中每个项目一个指示符,当前项目突出显示。单击指示器通常会将您滚动到指定的项目。

我需要 JavaScript 吗? (我假设是这样。)我应该如何检测当前可见的项目?

【问题讨论】:

    标签: javascript html css


    【解决方案1】:

    在现代浏览器中处理这个问题的方法是使用IntersectionObserver。在下面的示例中,只要其中一个子元素超过 50% 阈值,IntersectionObserver 就会触发其回调,使其成为具有最大 intersectionRatio 的元素。发生这种情况时,我们会根据当前选定项的索引重新渲染指示器。

    请注意,Safari 在实现对 IntersectionObserver 的支持方面有点晚了。 IntersectionObserver just became available in Safari 12.1。您可以使用IntersectionObserver polyfill 来支持旧版浏览器,使用此脚本标签:

    <script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
    

    额外提示:您可以使用scroll-behavior: smoothscrollIntoView 调用设置动画。

    var carousel = document.querySelector('.carousel');
    var indicator = document.querySelector('#indicator');
    var elements = document.querySelectorAll('.carousel > *');
    var currentIndex = 0;
    
    function renderIndicator() {
      // this is just an example indicator; you can probably do better
      indicator.innerHTML = '';
      for (var i = 0; i < elements.length; i++) {
        var button = document.createElement('button');
        button.innerHTML = (i === currentIndex ? '\u2022' : '\u25e6');
        (function(i) {
          button.onclick = function() {
            elements[i].scrollIntoView();
          }
        })(i);
        indicator.appendChild(button);
      }
    }
    
    var observer = new IntersectionObserver(function(entries, observer) {
      // find the entry with the largest intersection ratio
      var activated = entries.reduce(function (max, entry) {
        return (entry.intersectionRatio > max.intersectionRatio) ? entry : max;
      });
      if (activated.intersectionRatio > 0) {
        currentIndex = elementIndices[activated.target.getAttribute("id")];
        renderIndicator();
      }
    }, {
      root:carousel, threshold:0.5
    });
    var elementIndices = {};
    for (var i = 0; i < elements.length; i++) {
      elementIndices[elements[i].getAttribute("id")] = i;
      observer.observe(elements[i]);
    }
    .carousel {
      scroll-snap-type: x mandatory;
      -webkit-overflow-scrolling: touch;
      width: 100vw;
      white-space: nowrap;
      overflow-x: scroll;
      scroll-behavior: smooth
    }
    
    .carousel > * {
      display: inline-block;
      scroll-snap-align: start;
      width: 100vw;
      height: 80vh;
    }
    
    #x {
      background-color: pink;
    }
    #y {
      background-color: lightcyan;
    }
    #z {
      background-color: lightgray;
    }
    <script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
    <div class="carousel">
    <div id="x">x</div>
    <div id="y">y</div>
    <div id="z">z</div>
    </div>
    <div id="indicator">• ◦ ◦</div>

    【讨论】:

    • 您能否编辑您的 Javascript 代码以不创建带点的按钮,而是创建一个 div 元素,并在该 div 内创建一个内部 span 元素,whitch 将根据位置从左向右移动你观察轮播的内容是什么?
    • 您所描述的是滚动条。只需使用滚动条! css-tricks.com/the-current-state-of-styling-scrollbars
    • 在我看来,正确的解决方案是这样的:active.intersectionRatio&gt; 0.5 因为向右滚动时,首先调用第二张幻灯片,然后调用第一张幻灯片。正因为如此,点上升到错误的地方(1号)。上面的代码解决了这个问题,因为一张幻灯片降低了比率(例如 0.48),而另一张幻灯片增加了(例如 0.52)。
    • 不,它对我来说效果很好:threshold: 1active.intersectionRatio &gt;= 1
    猜你喜欢
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    • 2019-11-08
    • 2020-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2015-09-23
    相关资源
    最近更新 更多