Development/Javascript
[Swiper] 세로형 슬라이드 배너 제작하기 / vertical
레오나르도 다빈츠
2023. 8. 12. 17:29
Swiper로 개발할 때 가로형에 슬라이드가 1개인 것만 구현해봤었는데 이번 개발건에 세로형+여러 슬라이드 구성이 필요했다.
이번에는 예전과 달리 "공통"이라는 키워드에 맞춰 개발하려고 노력했고 그것을 기록하는 글..✏️
vue-awesome-swiper를 사용했다.
$ npm i vue-awesome-swiper
📄 공통컴포넌트
- prop으로 넘어온 isVertical(=세로여부) 값에 따라 style이 나뉘어진다.
- 공통적으로 사용하려면 콘텐츠 영역은 분리돼야 할 것 같아 <swiper-slide> 영역은 <slot>으로 따로 받아서 구현했고, 콘텐츠 영역의 width, height를 받아서 슬라이드 배너의 너비와 높이를 계산했다.
<template>
<div
class="floating-banner"
:style="{ width: `${isVertical ? contentWidth : computedLength}px` }"
>
<div class="floating-banner__contents">
<swiper
ref="floatingBannerSwiper"
:style="isVertical ? { height: `${computedLength}px` } : { width: `${computedLength}px` }"
:options="swiperOption"
>
<!-- 콘텐츠 영역은 이렇게 슬롯으로 받았다. -->
<slot></slot>
</swiper>
<button
class="floating-button__up w-swiper-button-prev"
:class="!isVertical && 'is-horizontal'"
>
<IconArrowUp />
</button>
<button
class="floating-button__down w-swiper-button-next"
:class="!isVertical && 'is-horizontal'"
>
<IconArrowDown />
</button>
</div>
</div>
</template>
다음은 script 부분이다.
- isVertical을 prop으로 받아 세로형, 가로형으로 바로 변경할 수 있도록 처리했다. Swiper의 세로형은 높이를 따로 지정해주어야하는데 computed의 computedLength가 그 역할을 수행한다.
- Swiper 옵션 중 direction에 'vertical'을 준다.
<script>
import { Swiper } from 'vue-awesome-swiper'
export default {
name: 'FloatingSideBanner',
components: { Swiper },
props: {
list: {
type: Array,
required: true,
},
// 노출할 콘텐츠의 개수
count: {
type: Number,
default: 3,
},
// 각 콘텐츠의 너비 (단위: px)
contentWidth: {
type: Number,
required: true,
},
// 각 콘텐츠의 높이 (단위: px)
contentHeight: {
type: Number,
required: true,
},
// 콘텐츠 사이의 간격 (단위: px)
gap: {
type: Number,
default: 10,
},
// 슬라이드 속도
speed: {
type: Number,
default: 5,
},
useAutoplay: {
type: Boolean,
default: true,
},
useLoop: {
type: Boolean,
default: true,
},
isVertical: {
type: Boolean,
default: true,
},
},
data() {
return {
delay: this.speed,
swiperOption: {
direction: this.isVertical ? 'vertical' : 'horizontal', // 가로형, 세로형
effect: 'slide',
slidesPerView: this.count,
spaceBetween: this.gap,
loop: this.useLoop,
simulateTouch: false, // 사용자가 터치하여 슬라이드를 넘기는 설정
navigation: { // 버튼 클래스를 연결해줘야 한다.
nextEl: '.w-swiper-button-next',
prevEl: '.w-swiper-button-prev',
},
},
}
},
computed: {
swiper() {
return this.$refs.floatingBannerSwiper.$swiper
},
// 여기서 높이를 설정한다.
computedLength() {
return this.contentHeight * this.count + this.gap * (this.count - 1)
},
},
created() {
this.init()
},
methods: {
init() {
if (this.useAutoplay) {
this.swiperOption = {
autoplay: {
delay: this.delay * 1000,
disableOnInteraction: false,
},
...this.swiperOption,
}
}
},
},
}
</script>
다음은 style 영역이다.
가로형, 세로형 여부에 따라 prev, next 버튼을 transform의 rotate 속성으로 뒤집어주었고 위치를 변경해주었다.
<style lang="scss" scoped>
.floating {
&-banner {
z-index: 10;
position: absolute;
top: 50%;
transform: translateY(-50%);
.swiper-container {
width: 100%;
margin: 0 auto;
}
&__contents {
display: flex;
justify-content: center;
}
}
&-button {
:is(&__up, &__down) {
position: absolute;
cursor: pointer;
z-index: 5;
border: none;
background-color: transparent;
&.is-horizontal {
top: 50%;
transform: translateY(-50%);
}
}
&__up {
top: -12px;
transform: translateY(-100%);
&.is-horizontal {
left: 0px;
transform: translate(-100%, -50%) rotate(-90deg);
}
}
&__down {
bottom: -12px;
transform: translateY(100%);
&.is-horizontal {
right: 0;
transform: translate(100%, -50%) rotate(-90deg);
}
}
}
}
</style>
📄 컴포넌트 호출부
<floating-side-banner
:list="floatingBannerList"
:content-width="160"
:content-height="160"
:gap="12"
>
<swiper-slide v-for="item in floatingBannerList">
<div class="banner-content">
{{ item.content }}
</div>
</swiper-slide>
</floating-side-banner>
floatingBannerList: [
{ content: 0 },
{ content: 1 },
{ content: 2 },
{ content: 3 },
{ content: 4 },
{ content: 5 },
{ content: 6 },
]
"간단한 prop 변수를 몇 개 수정하는 것 만으로 가로형, 세로형을 자유로이 변경 할 수 있을까?"로 시작된 고민의 늪.
prop으로 온갖 값을 받았다가 다시 지웠다가 하며 지금 내가 생각할 수 있는, 이 컴포넌트를 구성하기 위한 최소한의 값으로 구성한 것 같다.
(미래의 내 자신아.. 평가해줘..!!!!)
개발 할 때는 머리싸매며 고민했는데 적고보니까 별게 없다...🤔
다음부터는 codepen 링크까지 넣어봐야겠다.