4 분 소요

포트폴리오 웹 메인 페이지 무한 이미지 슬라이드 기능

이미지가 1 → 2 → 3 → 4 → 1 → 2 → 3 → 4 … 로 오른쪽에서 왼쪽으로 무한 슬라이드 될 때

4에서 1로 넘어갈 때 어색하게 왼쪽 1번째로 돌아가는 것이 아닌

4 → 5로 넘어가는 것처럼 보이게 만들었다.


html

<body class="preload">
    <header>
        <div id="header">
            <div class="header-container clearfix">
                <div class="header-logo">
                    <a href="#"><img src="../img/demuuLogoB.png"></a>
                </div>
                <div class="header-menu">
                    <ul>
                        <li>
                            <a href="">Portfolio</a>
                        </li>
                        <li>
                            <a href="">Gallery</a>
                        </li>
                        <li>
                            <a href="https://preasim.github.io">Blog</a>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </header>

    <div class="container">
        <ul class="carosel clearfix">
          <li>
            <div class="img-bx widthUp">
              <img src="../img/banner1.png" alt="banner1" />
            </div>
          </li>
          <li>
            <div class="img-bx">
              <img src="../img/banner1.png" alt="banner2" />
            </div>
          </li>
          <li>
            <div class="img-bx">
              <img src="../img/banner1.png" alt="banner3" />
            </div>
          </li>
          <li>
            <div class="img-bx">
              <img src="../img/banner1.png" alt="banner4" />
            </div>
          </li>
        </ul>
        <div class="Text">
            <h1 class="text1">UNCOVER</h1>
            <h1 class="text2">TEST</h1>
            <h1 class="text2">MORE</h1>
            <h1 class="text2">HUGO</h1>
        </div>
    </div>
</body>
<script src="./main.js" type="module"></script>


css

@import url("./reset.css");

#header {
    position: relative;
}
.header-container {
    margin-top: 20px;
    overflow: hidden;
}

.header-logo {
    display: inline-block;
    margin-left: 35px;
}
.header-logo img {
    width: 120px;
}

.header-menu {
    display: block;
    float: right;
}
.header-menu ul {
    overflow: hidden;
    margin-right: 35px;
    list-style: none;
}
.header-menu li {
    float: left;
    list-style: none;
    display: list-item;
    line-height: 3.25;
}
.header-menu li a {
    margin: 0 20px;
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: #757575;
}
.header-menu li a:hover {
    color: #000;
}

/* ------------- banner animation ----------- */
.container {
  height: calc(100vh - 220px);
  margin-top: 20px;
  overflow: hidden;
}

.carosel {
  width: 400vw;
  transition: all 2s;
}

.carosel li {
  width: 100vw;
  float: left;
  display: flex;
  justify-content: center;
  align-items: center;
}

.img-bx {
  transition: all 1s;
  width: 35%;
  max-height: 40%;
  overflow: hidden;
}

.img-bx.widthUp {
  width: 40%;
}

.Text{
  width: 100vw;
  height: 350px;
  position: absolute;
  top: calc(100vh - 48vh - 175px);
  left: 0%;
  overflow: hidden;
  text-align: center;
}

.Text h1 {
  position: absolute;
  top: -300%;
  display: inline-block;
  left: calc(100% - 50vw - 50%);
  width: 100%;
  height: 300px;
  font-size: 18rem;
  transition: all 1.3s;
  transform: rotate(0.03deg);
  opacity: .9;
}

.Text .text2 {
  font-size: 25rem;
  letter-spacing: 2px;
}

.Text h1.activeAnimation{
  top: 0%;
}

.Text h1.activeAnimation.deActiveAnimation{
  top: 150%;
}

.Text h1.restAnimation{
  transition: none !important;
  top: -150%;
}


Js (slideAnimation.js)

화면 가운데서 옆으로 무한 슬라이드 되는 이미지 (1 → 2 → 3 → 4 → 1 → 2 … 반복)

import { changeTextAnimation } from 
"./TextAnimation.js";

const carouselUl = document.querySelector(".carosel");
const innerWidth = window.innerWidth;
const transionTime = 1;
//가장 처음 이미지가 줄어드는 시간을 조절하는 변수 현재 3초
const firstImageScaleDownTiming = 3 * 1000;
//1000은 transition이 끝나자 마자 scaleUp시작
let scaleUpTiming = transionTime * 1200;
//스케일 up이 끝나고 다시 줄어들 타이밍 1000은 1초 뒤
const scaleDownTiming = scaleUpTiming + transionTime * 1000 + 1000;
let setTimeOutTime = 0;
let timeId = "";
let currentItemLength = 0;
let currentSlide = 1;
let timer = 4000;
const createCopy = () => {
  const caroselItem = document.querySelectorAll(".carosel li");
  const copyLastItem = caroselItem[caroselItem.length - 1].cloneNode(true);
  const copyFirstItem = caroselItem[0].cloneNode(true);
  copyFirstItem.childNodes[1].classList.remove("widthUp");
  carouselUl.insertAdjacentElement("afterbegin", copyLastItem);
  carouselUl.insertAdjacentElement("beforeend", copyFirstItem);
  setCarouselWidth();
};

const setCarouselWidth = () => {
  currentItemLength = document.querySelectorAll(".carosel li").length;
  carouselUl.style.width = currentItemLength * innerWidth + "px";
  initSlidePosition();
};

const initSlidePosition = () => {
  let moveX = currentSlide * innerWidth;
  carouselUl.style.transition = "0s";
  carouselUl.style.transform = `translateX(-${moveX}px)`;
  autoPlay(timer);
  firstSlideInit();
};

/**
 * 처음 이미지 축소되는 시간은 settimeout 시간 바꾸면 됌
 */
const firstSlideInit = () => {
  const Slide = document.querySelectorAll(".carosel li div")[1];
  changeTextAnimation(0);
  setTimeout(() => {
    Slide.classList.remove("widthUp");
  }, firstImageScaleDownTiming);
};

const imageScaleDown = (currentSlide) => {
  setTimeout(() => {
    const Slide = document.querySelectorAll(".carosel li div");
    Slide[currentSlide].classList.remove("widthUp");
  }, scaleDownTiming);
};

const imageScaleUp = (currentSlide) => {
  setTimeout(() => {
    const Slide = document.querySelectorAll(".carosel li div");
    Slide[currentSlide].classList.add("widthUp");
  }, scaleUpTiming);
};

const fistSlideDownAni = () => {
  const Slide = document.querySelectorAll(".carosel li div")[1];
  setTimeout(() => {
    console.log('실행')
    Slide.style.transition = `${transionTime}s`;
    Slide.classList.remove("widthUp");
  }, scaleDownTiming - (scaleUpTiming + (transionTime * 1000)));
};

const imageSlide = () => {
  carouselUl.style.transition = `${transionTime}s`;
  changeTextAnimation(currentSlide);
  currentSlide++;
  let moveX = currentSlide * innerWidth;
  carouselUl.style.transform = `translateX(-${moveX}px)`;
  imageScaleUp(currentSlide);
  imageScaleDown(currentSlide);
  if (currentSlide === currentItemLength - 1) {
    imageScaleUp(currentSlide);
    imageScaleUp(1);
    clearInterval(timeId);
    transionTime === 1
      ? (setTimeOutTime = 1000 + scaleUpTiming)
      : (setTimeOutTime = transionTime * 1000 + scaleUpTiming);
    setTimeout(() => {
      currentSlide = 1;
      carouselUl.style.transition = "0s";
      moveX = currentSlide * innerWidth;
      carouselUl.style.transform = `translateX(-${moveX}px)`;
      fistSlideDownAni();
      setTimeout(() => {
        changeTextAnimation(currentSlide);
        currentSlide++;
        moveX = currentSlide * innerWidth;
        carouselUl.style.transition = `${transionTime}s`;
        carouselUl.style.transform = `translateX(-${moveX}px)`;
        imageScaleUp(currentSlide);
        imageScaleDown(currentSlide);
        autoPlay(timer);

      }, timer - (transionTime * 1000 + scaleUpTiming));
    }, setTimeOutTime);
  }
};

const autoPlay = (time) => {
  timeId = setInterval(imageSlide, time);
};

export const initCaroselUl = () => {
  createCopy();
};


Js (TextAnimation.js)

화면 가운데에서 상하로 슬라이드 되는 텍스트

export const changeTextAnimation = (currentSlide) => {
    const getAllText = document.querySelectorAll('.Text h1');
    switch( currentSlide ){
      case 0:
        firstAndlastAnimation();
        break
      case 1:
        TextAnimation(currentSlide);
        break;
      case 2:
        getAllText[currentSlide].classList.add('activeAnimation');
        TextAnimation(currentSlide);
        break;
      case 3:
        getAllText[currentSlide].classList.add('activeAnimation');
        TextAnimation(currentSlide);
        break;
      case 4:
        firstAndlastAnimation(currentSlide);
        break;
  
    }
  }
  
  //가장 처음 , 첫번째 ,마지막을 제외한 애니메이션 처리
  const TextAnimation = (currentSlide) => {
    const getAllText = document.querySelectorAll('.Text h1');
    getAllText[currentSlide].classList.remove('restAnimation')
    getAllText[currentSlide].classList.add('activeAnimation')
    setTimeout(() => {
      getAllText[currentSlide].classList.add('deActiveAnimation');
    },4000)
    setTimeout(() => {
      getAllText[currentSlide].classList.add('restAnimation');
      getAllText[currentSlide].classList.remove('deActiveAnimation');
      getAllText[currentSlide].classList.remove('activeAnimation');
    },5000)
  }
  
  const firstAndlastAnimation = () => {
    const getAllText = document.querySelectorAll('.Text h1');
    getAllText[0].classList.remove('restAnimation')
    getAllText[0].classList.add('activeAnimation')
    setTimeout(() => {
      getAllText[0].classList.add('deActiveAnimation');
    },4000)
    setTimeout(() => {
      getAllText[0].classList.add('restAnimation');
      getAllText[0].classList.remove('deActiveAnimation');
      getAllText[0].classList.remove('activeAnimation');
    },5000)
  }
  
  window.addEventListener('load',() => {
    document.body.classList.remove('preload');
  })

댓글남기기