In this tutorial, you will learn how to create a circular card slider with CSS and Vue.js. When a card is clicked, it is then flipped to reveal the content of its other side. Watch the video below for a detailed tutorial.
<body>
<div id="container" @mouseup="documentMouseUp($event)">
<div id="cards-container">
<div id="cards">
<div class="card default" @mousedown="cardsMouseDown($event)" @mouseup="cardsMouseUp($event)">
<div class="front"></div>
<div class="back">
<img src="joker.png">
</div>
</div>
<div v-for="index in 10" class="card" @mousedown="cardsMouseDown($event)" @mouseup="cardsMouseUp($event)">
<div class="front"></div>
<div class="back" v-text="index"></div>
</div>
</div>
</div>
</div>
<script>
var app = new Vue({
el: '#container',
data: {
container: null,
cardsContainer: null,
cards: [],
cardsLength: 0,
calcDeg: 0,
extraDeg: 0,
currentCard: null,
clickedCardIndex: null,
},
mounted:function(){
this.container = document.getElementById('container')
this.cardsContainer = document.getElementById('cards-container')
this.cards = [...document.getElementsByClassName('card')]
this.cardsLength = this.cards.length
this.calcDeg = 270/this.cardsLength
this.currentCard = this.cards[0]
this.rotationPosition()
},
methods: {
rotationPosition: function(exceptIndex) {
exceptIndex = exceptIndex | 0;
var i = 1;
for (var x = 0; x < this.cardsLength; x++) {
var card = this.cards[x]
this.extraDeg = exceptIndex > this.cardsLength/2 ? 360 : 0
if(x === exceptIndex) {
card.classList.add('active')
card.style.transform = 'rotate(' + this.extraDeg + 'deg)'
} else {
card.style.transform = 'rotate(' + ( (i * this.calcDeg) + 45 ) + 'deg)'
i++
}
}
},
documentMouseUp: function(e) {
this.clickedCardIndex = null
},
cardsMouseDown: function(e) {
if(this.clickedCardIndex == null && e.which == 1) {
this.clickedCardIndex = this.cards.indexOf(e.target.parentNode)
}
},
cardsMouseUp: function(e) {
if(this.clickedCardIndex === this.cards.indexOf(e.target.parentNode)) {
this.currentCard = e.target.parentNode
this.pushIndex(this.cards.indexOf(e.target.parentNode))
}
},
pushIndex: function(index) {
for (var j = 0; j < this.cardsLength; j++) {
this.cards[j].classList.remove('active')
}
this.rotationPosition(index)
}
}
})
</script>
</body>
body {
background: #2e3537;
margin: 0;
font-family: 'Roboto', sans-serif;
}
#container {
height: 100vh;
text-align: center;
display: flex;
justify-content: center;
}
.card {
width: 74px;
height: 100px;
background-color: #0e5d92;
box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.1);
border-radius: 3px;
position: absolute;
top: 33%;
margin-left: -37px;
color: white;
padding: 7px;
box-sizing: border-box;
cursor: pointer;
transform-origin: center 175%;
-webkit-transform-origin: center 175%;
-ms-transform-origin: center 175%;
-moz-transform-origin: center 175%;
transition: transform 0.5s;
-webkit-transition: transform 0.5s;
-ms-transition: transform 0.5s;
-moz-transition: transform 0.5s;
}
.card.default img {
width: 50px;
margin-top: 15px;
}
.card .front {
height: 100%;
background-image: url('logo.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.card .front img {
width: 50px;
}
.card .back {
display: none;
text-align: center;
color: #0e5d92;
font-size: 30px;
font-weight: 900;
line-height: 80px;
}
.card.active .front {
display: none;
}
.card.active .back {
display: block;
}
.card.active {
background-color: #dcdcdd;
}
.card:not(.active):hover {
background-color: #1c81c5;
}