삼각함수 - 원형 슬라이드
by jinam yu
HTML
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<div id="app">
<div class="viewport">
<ul class="slide" :style="getStyles()">
<li
v-for="i in len"
:style="getPosition(i)"
:class="{ active: isActive(i) }"
>
<button type="button">
<img :src="'https://placeimg.com/480/640/' + i" alt="" />
</button>
</li>
</ul>
<div class="control">
<button type="button" @click="prev"><i class="fa-solid fa-chevron-left"></i></button>
<button type="button" @click="next"><i class="fa-solid fa-chevron-right"></i></button>
</div>
</div>
</div>
SCSS
html,
body,
#app {
width: 100%;
height: 100%;
position: relative;
}
#app {
background-color: #363636;
}
.viewport {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.slide {
position: absolute;
left: 0;
top: 0;
list-style: none;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
transition: transform 0.75s cubic-bezier(0.165, 0.84, 0.44, 1);
li {
width: 20%;
height: 0%;
font-size: 0;
position: absolute;
& > button {
width: 100%;
position: relative;
padding-bottom: 130%;
background-color: #999;
border: 0;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
box-shadow: 0 4px 16px 1px rgba(#000, 0.5);
img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
}
&:hover {
img {
transform: scale(1.15);
}
}
}
}
li.active {
button {
img {
transform: scale(1.15);
}
}
}
}
.control {
position: absolute;
left: 50%;
bottom: 24px;
transform: translate(-50%, -50%);
button {
text-transform: uppercase;
line-height: 1;
border: 0;
background-color: transparent;
font-size: 22px;
font-weight: 700;
margin-left: 8px;
margin-right: 8px;
cursor: pointer;
color: white;
}
}
JavaScript
const cnt = 10;
const len = cnt * 2;
new Vue({
el:'#app',
data: {
len,
radius: 0,
rotate:0,
current:1,
},
methods: {
prev() {
this.move(this.current + 1);
},
next() {
this.move(this.current - 1);
},
move(i){
this.rotate = ((i - 1) / len) * 360;
this.current = i;
},
getStyles(){
const y = window.innerWidth - window.innerWidth / 4;
return { top: `${y}px`, transform: `rotate(${this.rotate}deg)` };
},
getPosition(i){
const index = i - 1;
const step = ((2 * Math.PI) / len) * index;
const cos = Math.cos(step - Math.PI / 2) * this.radius;
const sin = Math.sin(step - Math.PI / 2) * this.radius;
const x = cos;
const y = sin;
const r = (index / len) * 360;
return {
left: `calc(50% - ${x}px)`,
top: `calc(50% + ${y}px)`,
zIndex: y,
transform: `translate(-50%, -50%) rotate(${-r}deg)`,
transformOrigin: "center",
};
},
isActive(i){
let x = this.current % len;
if (x === 0) x = len;
if (x < 0) x = len + x;
return x === i;
},
resize() {
this.radius = window.innerWidth;
},
},
mounted(){
window.addEventListener("resize", this.resize);
this.resize();
}
})