기본 콘텐츠로 건너뛰기

한쪽 방향으로 계속 이동하는 텍스트, 무한롤링 공지사항, 대시보드 한 줄 정보, animation, requestAnimationFrame - css + javascript + html

한쪽 방향으로 계속 이동되지만 마우스를 가져가면 멈추고, 마우스가 나가면 다시 이동하는 효과



css 버전 - animation

html

<div class="wrap">
  <div class="txt_box" @mouseenter="stopNoti(true)" @mouseleave="stopNoti(false)">
    <a href="공지1">공지1</a>
    <a href="공지2">공지2</a>
    <a href="공지3">공지3</a>
  </div>
</div>

css

/* dlsplay:flex 한 이유는 .txt_box가 복제되어서 들어가서 라인을 맞추려고 */
.wrap{
  display:flex;
  width:1000px;
  overflow:hidden;
}

.txt_box{
  display:flex;
  align-items:center;
  animation:leftToRight 20s linear infinite;
}

/* 마우스가 오버되면 정지 */
.txt_box.on{
  animation-play-state:paused;
}

/* 
  왼쪽에서 오른쪽 이동.
  javascript에서 .txt_box를 복제해서 넣어서 -100% -> 0%.
*/
@keyframes leftToRight {
  from{
    transform:translateX(-100%);
  }
  to{
    transform:translateX(0%);
  }
}
......

js


// 이동되는 영역 복제해서 넣기
let cloneBox = document.querySelector(".txt_box").cloneNode(true);
document.querySelector(".wrap").append(cloneBox);

// 왼쪽에서 오른쪽으로(css 정의) 이동하기
stopNoti = (bl) => {
  // 멈춤
  if (bl) {
    document.querySelectorAll(".txt_box").forEach((ele, idx) => {
      ele.classList.add("on");
    })
  }
  // 이동하기
  else {
    document.querySelectorAll(".txt_box").forEach((ele, idx) => {
      ele.classList.remove("on");
    })
  }
}



js 버전 - requestAnimationFrame

html

<div id="rolling" v-cloak>
  <div class=" move_box" @mouseenter="moveStop(true)" @mouseleave="moveStop(false)">
    <div class="move_area" :style="'transform:translateX('+ info.leftx +'%)'">
      <div class="move_wrap">
        <a href="공지1">공지1</a>
        <a href="공지2">공지2</a>
        <a href="공지3">공지3</a>
      </div>
    </div>
  </div>
</div>

css

/* dlsplay:flex 한 이유는 .move_wrap이 복제되어서 들어가서 라인을 맞추려고 */
.move_area{display:flex;}
......

js (vuejs 사용)

const {createApp, reactive, computed, onMounted} = Vue;
const smove = {
  setup() {
    // ref() 를 사용하면 js에선 .value로 찾아감(예: info.value.leftx)
    // : dom에는 .value 없음(예: info.leftx)
    // reactive() 는 항상 .value 불필요
    const info = reactive({
      percent: 0,
      aniId: null,
      leftx: -50,// .move_wrap이 하나 더 복제되어서. move_area의 x위치를 -50% 로 이동
    })

    // 왼쪽에서 오른쪽으로 계속 이동
    leftMove = () => {
      info.leftx = -50 + (info.percent += 0.03);
      info.aniId = info.percent && requestAnimationFrame(leftMove);

      // 이동하는 영역의 x위치가 0%보다 크고, 50%가 넘어가면
      if(info.leftx > 0 && info.percent > 50){
        // 다시 0%에서 시작
        info.percent = 0;
      }
    }

    // 계속 움직이는 영역에
    const moveStop = (bo) => {
      // 마우스를 가져가면 멈춤
      if(bo) {
        cancelAnimationFrame(info.aniId);
      }
      // 마우스가 벗어나면 다시 움직임
      else {
        requestAnimationFrame(leftMove);
      }
    }

    onMounted(() => {
      // .move_wrap 복제
      let cloneWrap = document.querySelector(".move_wrap").cloneNode(true);

      // .move_area에 복제된거 넣음(prepend : 앞에 붙임,  append : 뒤에 붙임)
      document.querySelector(".move_area").append(cloneWrap);

      // 왼쪽에서 오른쪽으로 계속 이동
      requestAnimationFrame(leftMove);
    })

    return {
      info, moveStop,
    }
  }
};
createApp(smove).mount("#rolling");

메인 화면이나 대시보드 같은데서 공지사항 같은 한 줄 정보를 끊임없이 보여주는 효과로 사용할 수 있는게 두개 있다.
하나는 css의 animation 속성이고, 다른 하나는 javascript의 requestAnimationFrame이다.
둘 다 적용해보고 좀 더 편하게 사용가능 한 것으로 선택해보자.


끝.