i am trying to make a number corousel but it wont update the active class for specific values in the html.
i am using vue js creating a cards array
and duplicating for infinite scrolling effect
this is working as intended
and calculating the active index based on the scroll position
<div class="wrapper" ref="onWrapper">
<i @click="handleClick('top')" class="pi pi-angle-up"></i>
<ul ref="onCorousel" class="corousel" @mousemove="dragging" @mousedown="dragStart" @mouseup="dragStop"
@scroll="infiniteScroll" @mouseleave="dragStop">
<li v-for="(card, index) in cards" :key="index" class="card" :class="{'active': card === this.cards[this.activeIndex]}">
<div class="img">{{ card }}</div>
<i @click="handleClick('bottom')" class="pi pi-angle-down"></i>
import { debounce } from 'lodash';
this.corousel = this.$refs.onCorousel
this.corouselChildrens = [...this.corousel.children];
const cardHeights = Array.from(this.corouselChildrens).map(card => card.offsetHeight);
this.maxCardHeight = Math.max(...cardHeights);
this.cardPerView = Math.floor(this.corousel.offsetHeight / this.maxCardHeight);
this.corouselChildrens.slice(-this.cardPerView).reverse().forEach(card => {
this.corousel.insertAdjacentHTML("afterBegin", card.outerHTML)
this.corouselChildrens.slice(0, this.cardPerView).forEach(card => {
this.corousel.insertAdjacentHTML("beforeEnd", card.outerHTML)
console.log(this.corousel)
this.corousel.classList.add("dragging")
this.startScrollTop = this.corousel.scrollTop
this.corousel.classList.remove("dragging")
if (!this.isDragging) return;
const deltaY = e.pageY - this.startY;
const newScrollTop = this.startScrollTop - deltaY;
this.corousel.scrollTop = Math.max(0, Math.min(newScrollTop, this.corousel.scrollHeight - this.corousel.offsetHeight));
this.corousel.scrollTop += -this.maxCardHeight
if (this.activeIndex === 0) {
this.corousel.scrollTop += this.maxCardHeight
if (this.activeIndex === 3) {
console.log(this.activeIndex)
console.log(this.cards[this.activeIndex])
infiniteScroll: debounce(function () {
if (this.corousel.scrollTop === 0) {
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.scrollHeight - (2 * this.corousel.offsetHeight);
this.corousel.classList.remove("no-transition");
} else if (Math.ceil(this.corousel.scrollTop) === this.corousel.scrollHeight - this.corousel.offsetHeight) {
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.offsetHeight;
this.corousel.classList.remove("no-transition");
background: linear-gradient(to left top, #031A9A, #8B53FF);
transform: translateX(+100%);
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.23)
grid-auto-rows: calc((100% / 3) - 12px);
scroll-snap-type: y mandatory;
.corousel::-webkit-scrollbar {
.corousel.no-transition {
.corousel.dragging .card {
scroll-snap-align: start;
/* transform: scale(1.2); */
<code><template>
<div class="wrapper" ref="onWrapper">
<i @click="handleClick('top')" class="pi pi-angle-up"></i>
<ul ref="onCorousel" class="corousel" @mousemove="dragging" @mousedown="dragStart" @mouseup="dragStop"
@scroll="infiniteScroll" @mouseleave="dragStop">
<li v-for="(card, index) in cards" :key="index" class="card" :class="{'active': card === this.cards[this.activeIndex]}">
<div class="img">{{ card }}</div>
</li>
</ul>
<i @click="handleClick('bottom')" class="pi pi-angle-down"></i>
</div>
</template>
<script>
import { debounce } from 'lodash';
export default {
data() {
return {
cards: [3, 4, 6, 8],
activeIndex: 1,
corousel: null,
isDragging: false,
startY: 0,
startScrollTop: 0,
firstCardHeight: null,
corouselChildrens: null,
cardPerView: null,
maxCardHeight: null
}
},
mounted() {
this.corousel = this.$refs.onCorousel
this.corouselChildrens = [...this.corousel.children];
const cardHeights = Array.from(this.corouselChildrens).map(card => card.offsetHeight);
this.maxCardHeight = Math.max(...cardHeights);
this.cardPerView = Math.floor(this.corousel.offsetHeight / this.maxCardHeight);
this.corouselChildrens.slice(-this.cardPerView).reverse().forEach(card => {
this.corousel.insertAdjacentHTML("afterBegin", card.outerHTML)
})
this.corouselChildrens.slice(0, this.cardPerView).forEach(card => {
this.corousel.insertAdjacentHTML("beforeEnd", card.outerHTML)
})
console.log(this.cards)
console.log(this.corousel)
},
methods: {
dragStart(e) {
this.isDragging = true
this.corousel.classList.add("dragging")
this.startY = e.pageY;
this.startScrollTop = this.corousel.scrollTop
},
dragStop() {
this.isDragging = false
this.corousel.classList.remove("dragging")
},
dragging(e) {
if (!this.isDragging) return;
const deltaY = e.pageY - this.startY;
const newScrollTop = this.startScrollTop - deltaY;
this.corousel.scrollTop = Math.max(0, Math.min(newScrollTop, this.corousel.scrollHeight - this.corousel.offsetHeight));
},
handleClick(id) {
if (id === 'top') {
this.corousel.scrollTop += -this.maxCardHeight
if (this.activeIndex === 0) {
this.activeIndex = 3
}
else {
this.activeIndex -= 1
}
}
if (id === 'bottom') {
this.corousel.scrollTop += this.maxCardHeight
if (this.activeIndex === 3) {
this.activeIndex = 0
}
else {
this.activeIndex += 1
}
}
console.log(this.activeIndex)
console.log(this.cards[this.activeIndex])
},
infiniteScroll: debounce(function () {
if (this.corousel.scrollTop === 0) {
console.log('top');
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.scrollHeight - (2 * this.corousel.offsetHeight);
this.corousel.classList.remove("no-transition");
} else if (Math.ceil(this.corousel.scrollTop) === this.corousel.scrollHeight - this.corousel.offsetHeight) {
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.offsetHeight;
this.corousel.classList.remove("no-transition");
}
}, 100)
}
}
</script>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
max-height: 100vh;
background: linear-gradient(to left top, #031A9A, #8B53FF);
}
.wrapper {
max-height: 900px;
height: 100%;
position: relative;
}
.wrapper i {
height: 50px;
width: 50px;
background: #fff;
text-align: center;
line-height: 50px;
border-radius: 50%;
cursor: pointer;
position: absolute;
transform: translateX(+100%);
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.23)
}
.wrapper i:first-child {
top: -22px;
}
.wrapper i:last-child {
bottom: -22px;
}
.wrapper .corousel {
height: 500px;
display: grid;
grid-auto-flow: row;
grid-auto-rows: calc((100% / 3) - 12px);
gap: 16px;
overflow-y: auto;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
scrollbar-width: 0;
}
.corousel::-webkit-scrollbar {
display: none;
}
.corousel.no-transition {
scroll-behavior: auto;
}
.corousel.dragging .card {
cursor: grab;
user-select: none;
}
.corousel.dragging {
scroll-snap-type: none;
scroll-behavior: auto;
}
.corousel .card {
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 8px;
list-style: none;
font-size: 100px;
}
.card .img {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 140px;
height: 140px;
}
.card.active {
/* transform: scale(1.2); */
background-color: red;
}
</style>
</code>
<template>
<div class="wrapper" ref="onWrapper">
<i @click="handleClick('top')" class="pi pi-angle-up"></i>
<ul ref="onCorousel" class="corousel" @mousemove="dragging" @mousedown="dragStart" @mouseup="dragStop"
@scroll="infiniteScroll" @mouseleave="dragStop">
<li v-for="(card, index) in cards" :key="index" class="card" :class="{'active': card === this.cards[this.activeIndex]}">
<div class="img">{{ card }}</div>
</li>
</ul>
<i @click="handleClick('bottom')" class="pi pi-angle-down"></i>
</div>
</template>
<script>
import { debounce } from 'lodash';
export default {
data() {
return {
cards: [3, 4, 6, 8],
activeIndex: 1,
corousel: null,
isDragging: false,
startY: 0,
startScrollTop: 0,
firstCardHeight: null,
corouselChildrens: null,
cardPerView: null,
maxCardHeight: null
}
},
mounted() {
this.corousel = this.$refs.onCorousel
this.corouselChildrens = [...this.corousel.children];
const cardHeights = Array.from(this.corouselChildrens).map(card => card.offsetHeight);
this.maxCardHeight = Math.max(...cardHeights);
this.cardPerView = Math.floor(this.corousel.offsetHeight / this.maxCardHeight);
this.corouselChildrens.slice(-this.cardPerView).reverse().forEach(card => {
this.corousel.insertAdjacentHTML("afterBegin", card.outerHTML)
})
this.corouselChildrens.slice(0, this.cardPerView).forEach(card => {
this.corousel.insertAdjacentHTML("beforeEnd", card.outerHTML)
})
console.log(this.cards)
console.log(this.corousel)
},
methods: {
dragStart(e) {
this.isDragging = true
this.corousel.classList.add("dragging")
this.startY = e.pageY;
this.startScrollTop = this.corousel.scrollTop
},
dragStop() {
this.isDragging = false
this.corousel.classList.remove("dragging")
},
dragging(e) {
if (!this.isDragging) return;
const deltaY = e.pageY - this.startY;
const newScrollTop = this.startScrollTop - deltaY;
this.corousel.scrollTop = Math.max(0, Math.min(newScrollTop, this.corousel.scrollHeight - this.corousel.offsetHeight));
},
handleClick(id) {
if (id === 'top') {
this.corousel.scrollTop += -this.maxCardHeight
if (this.activeIndex === 0) {
this.activeIndex = 3
}
else {
this.activeIndex -= 1
}
}
if (id === 'bottom') {
this.corousel.scrollTop += this.maxCardHeight
if (this.activeIndex === 3) {
this.activeIndex = 0
}
else {
this.activeIndex += 1
}
}
console.log(this.activeIndex)
console.log(this.cards[this.activeIndex])
},
infiniteScroll: debounce(function () {
if (this.corousel.scrollTop === 0) {
console.log('top');
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.scrollHeight - (2 * this.corousel.offsetHeight);
this.corousel.classList.remove("no-transition");
} else if (Math.ceil(this.corousel.scrollTop) === this.corousel.scrollHeight - this.corousel.offsetHeight) {
this.corousel.classList.add("no-transition");
this.corousel.scrollTop = this.corousel.offsetHeight;
this.corousel.classList.remove("no-transition");
}
}, 100)
}
}
</script>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
max-height: 100vh;
background: linear-gradient(to left top, #031A9A, #8B53FF);
}
.wrapper {
max-height: 900px;
height: 100%;
position: relative;
}
.wrapper i {
height: 50px;
width: 50px;
background: #fff;
text-align: center;
line-height: 50px;
border-radius: 50%;
cursor: pointer;
position: absolute;
transform: translateX(+100%);
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.23)
}
.wrapper i:first-child {
top: -22px;
}
.wrapper i:last-child {
bottom: -22px;
}
.wrapper .corousel {
height: 500px;
display: grid;
grid-auto-flow: row;
grid-auto-rows: calc((100% / 3) - 12px);
gap: 16px;
overflow-y: auto;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
scrollbar-width: 0;
}
.corousel::-webkit-scrollbar {
display: none;
}
.corousel.no-transition {
scroll-behavior: auto;
}
.corousel.dragging .card {
cursor: grab;
user-select: none;
}
.corousel.dragging {
scroll-snap-type: none;
scroll-behavior: auto;
}
.corousel .card {
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 8px;
list-style: none;
font-size: 100px;
}
.card .img {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 140px;
height: 140px;
}
.card.active {
/* transform: scale(1.2); */
background-color: red;
}
</style>
on the handle click event it just wont apply background red the html would be like this sometimes
<code><ul class="corousel">
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card active"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<code><ul class="corousel">
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card active"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
</ul>
</code>
<ul class="corousel">
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
<li class="card active"><div class="img">8</div></li>
<li class="card"><div class="img">3</div></li>
<li class="card active"><div class="img">4</div></li>
<li class="card"><div class="img">6</div></li>
</ul>
here the active class should be only one 8 but its not working as intended