몽땅뚝딱 개발자

[Swiper] 세로형 슬라이드 배너 제작하기 / vertical 본문

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 링크까지 넣어봐야겠다.
 
 
 

Comments