계발하는 개발자

[Vue + JS] 무한 롤링 배너 기능 구현하는 방법 본문

📌 Language/Javascript

[Vue + JS] 무한 롤링 배너 기능 구현하는 방법

dev_genie 2023. 9. 27. 15:36

일전에 학원에서 진행했던 초창기 프로젝트에서 marquee(움직이는 텍스트) 구현하듯이 좌측으로 롤링되는 무한 롤링배너를 또 구현해야 했다.

위에서 이미지 배너 뒤에 움직이는 텍스트가 marquee다.

기억 상으로 html+css 만으로 움직이게 했던 것 같다.

(이미지 배너는 다른 방법으로 구현했으며, 원래는 멈춰있다가 커서가 해당 슬라이드 영역을 한 번 건드리고 가면 그때부터 움직이고, 움직이는 슬라이드 위에 커서를 놓으면 움직임을 멈추도록 했다.)

 

이번엔 다른 색다른 방법으로 구현하고 싶어서 찾아봤더니 Javascript cloneNode 함수를 이용해서 구현하는 방법이 있었다.

그 원리는 즉슨, li를 감싸는 wrap이라는 요소가 있으면 wrap 요소를 clone해서 또 다른 wrap2 요소를 만들고,

display: flex 로 한 행에 배치시킨 다음에 css 애니메이션을 wrap 요소마다 적용하는 것이다.

 

무한 롤링 배너 만들기

무한 롤링 배너는 원본배너와 복제배너를 한 방향으로 이동시켜주면서 배너 2개가 번갈아가며 뷰포트에 나타나는 형식으로 실제 화면상에서 보이는 동작은 하나의 배너가 무한 롤링하는 것처럼 보이게 된다.

작동 원리

1. 애니메이션 초기 상태

배너1 복사한 후 클론한 배너를 .md_wrap(배너 부모박스) 뒤쪽에 삽입해준다.

그런 후에 부모박스에 display: flex 적용하여 한 줄에 배치시킨다. 배너1 끝부분이 약간 잘린 채로 뷰포트 화면에는 아직 배너1만 보이게 된다.(이때 배너1, 배너2 구분을 위해 각각의 배너에 고유id값을 부여한다.)

 

2. 배너 너비만큼 배너1, 2 왼쪽 이동

css 키프레임을 이용해 왼쪽 방향으로 이동하는 애니메이션을 적용시킨다.

배너1,2가 translateX(-100%)만큼 왼쪽 이동하면서 배너1은 뷰포트 바깥으로 밀려나게 되고,배너2는 앞서 배너1 초기 위치만큼 이동한다. 그래서 현재 화면에서는 배너2가 보이게 된다.

'0%'일 때: 배너의 원래 위치이며, 애니메이션의 시작 지점이다 (transform: translateX(0)).
'50%일 때': 배너1은 왼쪽으로 슬라이드하여 이동한다 (transform: translateX(-100%)).

 

3. 배너1이 배너2 뒤쪽으로 이동

배너1이 다시 오른쪽으로 이동해서 들어오게 된다 transform: translateX(100%).

배너2는 다시 -100%만큼 왼쪽으로 이동해서 (총 -200%) 뷰포트 화면 밖으로 나가게 된다.

그리고 이 과정이 반복되면서 무한 롤링 배너가 구현되는 것이다.

'50.01%일 때': 배너1 다시 오른쪽 방향으로 이동해서 배너2 뒤에 위치한다 (transform: translateX(100%).
'100%일 때': 배너2는 다시 -100%만큼 왼쪽 이동해서 (총 -200% 이동) 뷰포트 밖으로 나간다.

.md_wrap {
    overflow: hidden;
    display: flex;
    gap: -4px;
    
    ul {
        display: flex;

        li {
            width: 340px;
            height: 544px;
            margin: 0 8px;
            background-color: #fff;
            display: flex;
        }
    }
    // 롤링배너 애니메이션
    #roller1 {
        animation: rollingleft1 90s linear infinite;
    }
    #roller2 {
        animation: rollingleft2 90s linear infinite;
    }
}

@keyframes rollingleft1 {
    0% { transform: translateX(0)}
	50% { transform: translateX(-100%)}
	50.01% { transform: translateX(100%)}
	100% { transform: translateX(0)}
}

@keyframes rollingleft2 {
    0% {transform: translateX(0)}
    100% {transform: translateX(-200%)}
}

<!-- 4. 미디어섹션(컴포넌트)-->
<section class="main_media">
    <h3>Media</h3>
    <div class="md_wrap">
        <div class="md_list">
            <ul>
                <MedComp v-for="(v, i) in mData" :key="i" :matchmedia="v" :dpt1val="v.depth1" :dpt2val="v.depth2"/>
            </ul>
        </div>
    </div>
</section>

methods: {
        rollBan() {
            // 롤링 배너 복제본 생성 
            let roller = document.querySelector('.md_list');
            roller.id = 'roller1'; // 아이디 부여
            
            // 노드 복제 (기본값은 false, 자식 노드까지 원하면 true)
            let clone = roller.cloneNode(true);
            clone.id = 'roller2';
            document.querySelector('.md_wrap').appendChild(clone); // .md_wrap 하위 자식으로 넣기

            document.querySelector('#roller1').style.left = '0px';
            document.querySelector('#roller2').style.left = document.querySelector('.md_list > ul').offsetWidth + 'px';
        },
    }
<!-- 아래는 MedComp Template -->
<template>
  <li>
    <a href="#">
      <!-- 썸네일 출력 영역 -->
      <div class="media_thumb">
        <img v-bind:src="tumbimg" alt="대표썸네일" />
        <span class="mlogo">
          <img src="/images/logo/logo_y.jpg" alt="sns계정명" />
          shoopen_official
        </span>
      </div>
      <div class="media_depth">
        <!-- 상품1 출력 영역 -->
        <div class="prod1bx">
          <div class="left_img">
            <img v-bind:src="dpt1img" alt="상품이미지1" />
          </div>
          <div class="right_txt">
            <p>{{ dpt1name }}</p>
            <em>{{ setComma(dpt1price) }}</em>
          </div>
        </div>
        <!-- 상품2 출력 영역 -->
        <div class="prod2bx">
          <div class="left_img">
            <img v-bind:src="dpt2img" alt="상품이미지2" />
          </div>
          <div class="right_txt">
            <p>{{ dpt2name }}</p>
            <em>{{ setComma(dpt2price) }}</em>
          </div>
        </div>
      </div>
    </a>
  </li>
</template>

 

결과 화면

배너1,2가 순환 반복되면서 이동된다 :)

 

* 기능구현 참고자료

 

[Javascript] 자동 롤링 배너를 만들어보자!

빙글빙글 돌아가는 내 인생과 롤링 배너💫

velog.io

 

느낀점

구글링을 하며 찾은 다른 구현 방법을 이게 왜 원리가 이렇게 되는지를 내가 다시 따져보고 적용해보는 과정이 참 재밌었다!

그리고 이 과정에서 다른 사람은 어떤 방식으로 접근했는가를 살펴볼 수 있었어서 '아 이런 방식으로도 할 수 있구나' 하고 뇌가 말랑해진 느낌을 받았다. 

LIST
profile

dev_genie

@dev_genie

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!