JSFiddle - React, Tailwind, and code Playground
by dumptyd
HTML
<div class="item-wrapper"></div>
<button id="next">Next</button>
CSS
body {
font-family: 'Ubuntu', 'Arial';
text-align: center;
}
.item-wrapper {
position: relative;
height: 300px; width: 150px;
border: 1px solid #333;
margin: 50px auto;
overflow: hidden;
}
.item {
position: absolute;
height: 100px; width: 100%;
background-color: orange;
display: flex; align-items: center; justify-content: center;
border: 1px solid #ccc;
box-sizing: border-box;
}
.transition { transition: .25s all ease; }
JavaScript
const $ = document.querySelector.bind(document);
class ShitLooper {
constructor({
itemsCount = 7, itemHeight = 100,
prevSelector = '#prev', nextSelector = '#next',
parentSelector = '.item-wrapper'
}) {
[this.itemsCount, this.itemHeight] = [itemsCount, itemHeight];
const wrapper = $(parentSelector);
this.itemEls = Array(itemsCount).fill(true).map((item, idx) => {
const itemEl = document.createElement('DIV');
const top = idx * itemHeight;
[itemEl.attrtop, itemEl.style.top] = [top, `${top}px`];
itemEl.classList.add('item');
itemEl.textContent = `Item ${idx + 1}`;
wrapper.appendChild(itemEl);
return itemEl;
});
this.inTransition = false;
this.attachHandler(nextSelector, 1);
}
attachHandler(selector) {
$(selector).addEventListener('click', () => {
if (this.inTransition) return;
this.inTransition = true;
this.itemEls.forEach(itemEl => {
itemEl.classList.add('transition');
itemEl.attrtop -= this.itemHeight;
itemEl.style.top = `${itemEl.attrtop}px`;
});
const el = this.itemEls.shift();
this.itemEls.push(el);
el.attrtop = (this.itemEls.length - 1) * this.itemHeight;
el.ontransitionend = () => {
el.classList.remove('transition');
el.style.top = `${el.attrtop}px`;
el.ontransitionend = null;
this.inTransition = false;
};
});
}
}
new ShitLooper({ itemsCount: 10 });