Honeycam 2019-08-14 10-07-52

위와 같은 이미지 슬라이더(Image Slider)를 만들어보도록 하겠습니다.

설계

image

###

위 사진처럼 크게 네가지로 나누어 볼 수 있습니다.

1. 이미지 리스트

슬라이드에 넣어줄 이미지 list들을 가지고 있어야 합니다.

2. 좌 우 버튼

이번에 만들 방식은 버튼을 사용한 이미지 슬라이더(Image Slider)이기 때문에 좌 우 버튼을 만들어 줍니다.

3. 이미지가 보여질 div

이미지 리스트 중에서 현재 상태의 이미지만 보여줄 div가 필요합니다.

동작 방식

1. 이미지 리스트 배치

3.이미지가 보여질 div1.이미지 리스트를 넣어줍니다. 이미지가 보여질 div는 아래의 빨간 네모처럼 보여질 크기를 지정해놓습니다. 그리고 1.이미지 리스트에서 이미지 하나의 크기를 3.이미지가 보여질 div로 해놓게 되면 아래와 같은 형태가 됩니다.

image

하지만 이미지 슬라이더는 하나의 이미지만 보여줘야 하기 때문에 빨간 네모에서 발생한 overflowhidden시켜줘야 합니다 .

2. slide animation 구현

버튼을 눌렀을 때 이미지를 이동시키는 애니메이션은 transform : translate 속성을 사용해서 구현할 수 있습니다. 현재 선택된 이미지의 index가 selected이고 이미지의 크기가 300이기 때문에 아래와 같이 transform : translate를 300px단위로 해주면서 이미지가 이동하는 효과를 줄 수 있습니다.

<div
  v-bind:style="{'transform': 'translate(-' + (selected-1)*300 + 'px, 0px)'}"
></div>
- 오른쪽 버튼을 누를 경우

이미지 리스트는 x축 기준 - 방향으로 이동해야하기 때문에

transform: translate(-300px);
- 왼쪽 버튼을 누를 경우

이미지 리스트는 x축 기준 + 방향으로 이동해야하기 때문에

transform: translate(+300px);
- 슬라이드 결과

Honeycam 2019-08-14 11-07-53

3. 이미지 슬라이더 overflow : hidden

Honeycam 2019-08-14 10-57-21

overflow hidden을 하게 되면 위와 같이 선택된 사진만 보여줄 수 있습니다.

4. 추가 작업

추가로 첫 이미지일 경우에 오른쪽 버튼만 보여주고 마지막 이미지일 때는 왼쪽 버튼만 보여주는등 작업을 해주면 이미지 슬라이더로 충분히 작업할 수 있을 것 같습니다.

<template>
  <div class="Wrapper">
    <span v-on:click="pre" v-bind:class="{ hidden: selected == 1 }">
      <i class="fas fa-chevron-circle-left fa-2x left"></i>
    </span>
    <div
      class="imageContainer"
      v-bind:style="{
        transform: 'translate(-' + (selected - 1) * 300 + 'px, 0px)'
      }"
    >
      <div v-for="i in images">
        <div
          class="image"
          v-bind:style="{ 'background-image': 'url(' + i + ')' }"
        ></div>
      </div>
    </div>
    <span v-on:click="next" v-bind:class="{ hidden: selected == length }">
      <i class="fas fa-chevron-circle-right fa-2x right"></i>
    </span>
  </div>
</template>

<script>
export default {
  props: ["images"],
  data() {
    return {
      length: this.images.length,
      selected: 1
    };
  },
  mounted() {},
  methods: {
    next() {
      if (this.selected == this.length) {
        this.selected = 1;
      } else {
        this.selected = this.selected + 1;
      }
      console.log(this.selected);
    },
    pre() {
      if (this.selected == 1) {
        this.selected = this.length;
      } else {
        this.selected = this.selected - 1;
      }
      console.log(this.selected);
    }
  }
};
</script>

<style>
.Wrapper {
  position: relative;
  width: 300px;
  height: 300px;
  /* overflow: hidden; */
}
.imageContainer {
  display: flex;
  transition: 0.6s;
}
.image {
  height: 300px;
  width: 300px;
  background-size: cover;
  background-position: center center;
}

.left {
  position: absolute;
  left: 5px;
  top: 50%;
  cursor: pointer;
}

.right {
  position: absolute;
  right: 5px;
  top: 50%;

  cursor: pointer;
}
svg {
  z-index: 2;
  color: rgba(0, 0, 0, 0.2);
}
.hidden {
  display: hidden;
}
</style>