为 CSS 动力幻灯片添加分页(索引)指示器

Adding pagination (index) indicator for a CSS powered slideshow

我有一个简单的滑块,我使用新的CSS Scroll Snap module

现在我被困在如何向用户显示他们所在的页面上。在 Javascript 中,通常会这样做 like this or via bootstrap like this... 但我正在摸索如何检测和显示当前可见幻灯片的索引,因为到目前为止它只是一个 CSS 实现.有任何想法吗?或者我必须恢复到 js 滑块吗?

payload =  [{
 "url": "https://unsplash.it/801?random",
 "filter": "nashville"
}, {"url": "https://unsplash.it/802?random",
 "filter": "aden"
}, {
 "url": "https://unsplash.it/803?random",
 "filter": "mayfair"
}, {
 "url": "https://unsplash.it/804?random",
 "filter": "lofi"
}, {
 "url": "https://unsplash.it/805?random",
 "filter": "kelvin"
}, {
 "url": "https://unsplash.it/806?random",
 "filter": "mayfair"
}]

const init = function(){
 var slider = document.getElementById("slider");
 for (let i = 0; i < payload.length; i++){
  slider.innerHTML += "<section><figure class='" + payload[i].filter + "'><img src='" + payload[i].url + "' /> </figure></section>"; 
 }
 
 //cssScrollSnapPolyfill()
}
init();
img {
  display: inline-block;
  height: 98vh;
  -o-object-fit: cover;
     object-fit: cover;
  width: 100vw;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  overflow-y: hidden;
}

.slider {
  font-family: sans-serif;
  -ms-scroll-snap-type: x mandatory;
      scroll-snap-type: x mandatory;
  display: flex;
  -webkit-overflow-scrolling: touch;
  overflow-x: scroll;
}

section {
  min-width: 100vw;
  height: 100vh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  text-align: center;
  position: relative;
}

.pagination {
  display: inline-block;
  position: fixed;
  background: rgba(33, 33, 33, 0.9);
  color: #fff;
  text-align: center;
  border-radius: 13px;
  z-index: 4;
  width: 70px;
  top: 20px;
  right: 20px;
}

span {
  display: inline-block;
  line-height: 28px;
  vertical-align: middle;
}
<div class="slider" id="slider">
 <div class='pagination'> <span>1 / 5</span></div>
</div>

如何使用 css 滚动快照容器的当前滚动并将其除以幻灯片的宽度?

这个答案只是 Francesco Manicardi 之前建议的一个实现。你可以这样做:

const payload = [{
 "url": "https://unsplash.it/801?random",
 "filter": "nashville"
}, {
 "url": "https://unsplash.it/802?random",
 "filter": "aden"
}, {
 "url": "https://unsplash.it/803?random",
 "filter": "mayfair"
}, {
 "url": "https://unsplash.it/804?random",
 "filter": "lofi"
}, {
 "url": "https://unsplash.it/805?random",
 "filter": "kelvin"
}, {
 "url": "https://unsplash.it/806?random",
 "filter": "mayfair"
}];

const slider = document.getElementById("slider");
const pagination = document.querySelector('.pagination')

const init = function () {
 for (let i = 0; i < payload.length; i++) {
  slider.innerHTML += "<section><figure class='" + payload[i].filter + "'><img src='" + payload[i].url + "' /> </figure></section>";
 }

 initPagination();
}

init();


function initPagination() {
 pagination.innerHTML = `<span>1 / ${payload.length}<span>`;

 slider.addEventListener('scroll', function () {
  pagination.innerHTML = `<span>${getCurrentPageNumber()} / ${payload.length}<span>`;
 });
}

function getCurrentPageNumber() {
 const imgWidth = getSliderWidth() / payload.length;
 const imgShift = imgWidth * 0.5; // when to consider that the page has changed

 return Math.floor((slider.scrollLeft + imgShift) / imgWidth) + 1;
}

function getSliderWidth() {
 let width = 0;

 Array.from(slider.children).forEach(child => {
  const img = child.querySelector('img');

  if (img) {
   width += img.width;
  }
 });

 return width;
}
img {
 display: inline-block;
 height: 98vh;
 -o-object-fit: cover;
 object-fit: cover;
 width: 100vw;
}

* {
 box-sizing: border-box;
 margin: 0;
 padding: 0;
}

body {
 overflow-y: hidden;
}

.slider {
 font-family: sans-serif;
 -ms-scroll-snap-type: x mandatory;
 scroll-snap-type: x mandatory;
 display: flex;
 -webkit-overflow-scrolling: touch;
 overflow-x: scroll;
}

section {
 min-width: 100vw;
 height: 100vh;
 scroll-snap-align: start;
 scroll-snap-stop: always;
 text-align: center;
 position: relative;
}

.pagination {
 display: inline-block;
 position: fixed;
 background: rgba(33, 33, 33, 0.9);
 color: #fff;
 text-align: center;
 border-radius: 13px;
 z-index: 4;
 width: 70px;
 top: 20px;
 right: 20px;
}

span {
 display: inline-block;
 line-height: 28px;
 vertical-align: middle;
}
<div class="slider" id="slider"></div>
<div class='pagination'><span>1 / 5</span></div>

但在此解决方案中,我们假设所有图像的宽度都相同。

简化@Francesco 和@Andrew 的部分并添加去抖功能,我们得到:

payload =  [{
 "url": "https://s3.amazonaws.com/appforest_uf/f1573502006658x593350952181959600/IMG_7552.JPG",
 "filter": "nashville"
}, {"url": "https://source.unsplash.com/featured/?dinner",
 "filter": "aden"
}, {
 "url": "https://source.unsplash.com/featured/?dinner/1",
 "filter": "mayfair"
}, {
 "url": "https://source.unsplash.com/featured/?dinner/2",
 "filter": "lofi"
}, {
 "url": "https://source.unsplash.com/featured/?dinner/3",
 "filter": "kelvin"
}, {
 "url": "https://source.unsplash.com/featured/?lunch/4",
 "filter": "mayfair"
}]

 
const init = function(){
 const slider = document.querySelector('.slider');
 const pagination = document.querySelector('.pagination')
 pagination.innerHTML = `<span>1 / ${payload.length}<span>`;
 for (let i = 0; i < payload.length; i++){
  slider.innerHTML += "<section><figure class='" + payload[i].filter + "'><img src='" + payload[i].url + "' /> </figure></section>";
 }
}
init();

slider.addEventListener('scroll', _.debounce(function() { 
 //console.log(Math.round(slider.scrollLeft / slider.offsetWidth )+1);
 const pagination = document.querySelector('.pagination') 
 pagination.innerHTML = `<span>${Math.round(slider.scrollLeft / slider.offsetWidth )+1} / ${payload.length}<span>`;
}, 200)) //Lower this debounce number and note how the number of scroll events fired increases... We'd like to maintain just one scroll event.
img {
  display: inline-block;
  height: 70vh;
  -o-object-fit: cover;
     object-fit: cover;
  width: 100vw;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  overflow-y: hidden;
}

.slider {
  font-family: sans-serif;
  -ms-scroll-snap-type: x mandatory;
      scroll-snap-type: x mandatory;
  display: flex;
  -webkit-overflow-scrolling: touch;
  overflow-x: scroll;
}

section {
  min-width: 100vw;
  height: 100vh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  text-align: center;
  position: relative;
}

.pagination {
  display: inline-block;
  position: fixed;
  background: rgba(33, 33, 33, 0.9);
  color: #fff;
  text-align: center;
  border-radius: 13px;
  z-index: 4;
  width: 70px;
  top: 20px;
  right: 20px;
}

span {
  display: inline-block;
  line-height: 28px;
  vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

<div class="slider" id="slider">
 <div class='pagination'>
 </div>
</div>