<!DOCTYPE html>
<html>
<head>
<style>
.transition-element {
width: 200px;
height: 200px;
background-color: red;
position: relative;
}
</style>
</head>
<body>
<div class="transition-element"></div>
<script>
const element = document.querySelector('.transition-element');
// 클릭 이벤트 처리
element.addEventListener('click', function() {
const startPosition = parseInt(getComputedStyle(element).left);
const targetPosition = startPosition + 100; // 목표 위치
const duration = 1000; // 전환 시간 (1초)
const interval = 10; // 이동 간격 (ms)
let currentTime = 0;
function move() {
currentTime += interval;
const progress = Math.min(currentTime / duration, 1); // 진행 상태 (0~1)
const currentPosition = startPosition + (targetPosition - startPosition) * progress;
element.style.left = currentPosition + 'px';
if (progress < 1) {
setTimeout(move, interval);
}
}
move();
});
</script>
</body>
</html>
move 함수
가 호출되며, setTimeout을 사용하여 일정한 간격(interval)으로 요소를 이동시킨다.요소가 이동하기 위해서는 position: relative;
속성이 필요하다.
위 코드에서는 이동을 위해 left 속성을 사용하였다. 요소의 초기 위치가 왼쪽에서부터 이동할 거리보다 멀리 떨어져 있을 경우, 시작 위치(startPosition)를 조정해야 할 수도 있다.
아래 예제 코드는 주의 사항을 적용하여 Vue.js를 이용하려 작성한 예제코드이다.
바로 앞서 포스팅한 Font-awesome 태그와 함께 작성되었다.
<font-awesome-icon :icon="['fas', 'arrow-left']" class="arrowIcon" @click="goScroll('L')"/>
<div class="boardMenu"
ref="scrollable" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp"
>
<div v-for="board in getBoardCtgry" :key="board.boardSeq">
<router-link :to="{ path: '/onpoom/board', query: { seq: board.boardSeq } }">
<div class="boardTab" @click="handleTabClick(board.boardSeq)" :class="{ sel: selectedTab === board.boardSeq }">
{{board.boardName}}
</div>
</router-link>
</div>
</div>
<font-awesome-icon :icon="['fas', 'arrow-right']" class="arrowIcon" @click="goScroll('R')"/>
위 코드는 상단의 메뉴 tab에서 보이는 컴포넌트를 작성한 것이다. 각각이 router-link로 만들어져 있으며 query string으로 값을 가져와서 각각의 sel 태그를 활성화하였다.
사실 nested route를 쓰면 편하지만 이미 왼쪽 메뉴바를 구현해봐서 query-string을 이용하여 위 tab화면을 구현해보고 싶었다.
goScroll(direction) {
const startPosition = this.$refs.scrollable.offsetLeft/3;
const targetPosition = startPosition + 10; // 목표 위치
const duration = 500;
const interval = 10; // 이동 간격 (ms)
let currentTime = 0;
const move = () => {
currentTime += interval;
const progress = Math.min(currentTime / duration, 1); // 진행 상태 (0~1)
const currentPosition = startPosition + (targetPosition - startPosition) * progress;
if(direction==='L'){
this.$refs.scrollable.scrollLeft -= currentPosition;
}else{
this.$refs.scrollable.scrollLeft += currentPosition;
}
if (progress < 1) {
setTimeout(move, interval);
}
}
move();
},
mouse로 가로스크롤구현하는 코드를 보고싶다면 다음 포스팅을 참조하면 된다.
무큰 위 코드는 3번의 클릭으로 끝까지 naviage를 할 수 있는 코드이다.
참고로 this.$refs.scrollable.offsetLeft
는 위 사진의 주황색 선을 나타낸다.
startPosition
변수는 스크롤 가능한 요소의 현재 가로 스크롤 위치를 나타내고 offsetLeft
속성을 사용하여 요소의 가로 스크롤 위치를 구한다.
targetPosition
변수는 목표로 하는 가로 스크롤 위치를 나타낸다. 현재 위치에서 10만큼 이동하는 것을 목표로 설정한다.
이 값을 조정하여 이동 거리를 변경할 수 있다.
duration
변수는 애니메이션의 전체 시간을 나타낸다.
interval
변수는 이동 간격을 나타낸다. 10ms로 설정하여 0.01초마다 이동하도록 구현하였다.
currentTime
변수는 애니메이션의 현재 진행 시간을 나타낸다.
마지막으로 move
함수는 애니메이션을 실제로 실행하는 함수이다. currentTime
값을 업데이트하고 진행 상태를 계산하여 현재 위치를 결정한다.
이후 스크롤 가능한 요소의 scrollLeft 속성
을 업데이트하여 스크롤을 이동한다.
진행 상태가 1보다 작을 경우 재귀적으로 move
함수를 계속 호출하여 애니메이션을 진행해 나간다.