requestAnimationFrame()
(이하 raf)은 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 repaint가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출하게 한다.
쉽게 말해서 브라우저가 이제 매번 계속 화면을 그리는데, 변화된 화면을 그릴 준비가 완료 되었을 때 딱 그려준다고 볼 수 있다. 무언가를 최적화를 해서 애니메이션을 부드럽게 처리하는 기술이라고 생각하면 될 것 같다.
이전에는 setInterval()
을 사용했지만, setInterval()
은 프레임 유실이나 모바일 기기에서 배터리 사용량이 많아져 raf가 등장한 이후에는 주로 raf를 사용하고 있다.
window.requestAnimationFrame(callback);
callback : 다음 repaint를 위한 애니메이션을 업데이트할 때 호출할 함수.
예시를 들어 사용해보자.
<body>
<img class="image" src="/이미지경로" />
<div class="value">requestAnimationFrame</div>
<script>
const image = document.querySelector(".image");
const value = document.querySelector(".value");
requestAnimationFrame(() => {
console.log(0);
});
console.log(1);
</script>
</body>
보기에서 console
의 순서가 어떻게 될까요?
//console창
1
0
아래에 있는 console
이 먼저 실행되고, raf안에 있는 console
이 나중에 실행되는 걸 알 수 있고, 그리고 한 번씩만 실행이 된다.
여기서 알 수 있는 사실은 raf에는 지연효과가 있다는 사실을 기억해야한다! 기본적인 동작은 이렇게 되고, 함수에서 사용해보자!
<body>
<div class="container">
<img class="image" src="/이미지경로" />
<div class="value">requestAnimationFrame</div>
</div>
<script>
const image = document.querySelector(".image");
const value = document.querySelector(".value");
//2 yPos라는 변수를 하나 만들고 값을 0으로 줍니다.
let yPos = 0;
//1 render라는 함수 생성
const render = () => {
//3 innerHTML로 yPos를 출력
value.innerHTML = yPos;
//4 yPos 증가
yPos++
//6 애니메이션
requestAnimationFrame(render);
}
//5 render 함수 실행
render();
</script>
</body>
render
라는 함수를 만들고yPos
라는 변수를 하나 만들고 값을 0으로 준다.value
에 innerHTML
로 yPos
를 출력을 하고,render()
를 호출하면 0이 찍힌다.*여기서 innerHTML로 출력을 한다음에 1을 더했으니까 아직은 1을 더한게 의미가 없다.
render
함수를 아주 빠른 속도로 반복을 시키려고 한다. 그 때 우리가 여기다가 requestAnimationFrame
를 써주고 콜백함수 자리에 render
함수를 넣어주고 (5)의 render()
를 실행하면 이렇게 아주 빠른속도로 1씩 증가하게 된다.이 속도는 초당 60번을 목표로 하지만, 현재 컴퓨터의 상황이나 성능, 기타 등등 요소에 따라서 속도는 더 느려질 수 있다.. 어쨌든 초당 60회 가까이 반복을 하려고 노력을 하는 중이라는거..? 애니메이션으로 치면 60프레임을 목표로 빠르게 돌아간다.
그럼 이제 이미지를 가지고 raf를 이용해서 애니메이션을 구현해보자.
<body>
<div class="container">
<img class="image" src="/이미지경로" />
<div class="value">requestAnimationFrame</div>
</div>
<script>
const image = document.querySelector(".image");
const value = document.querySelector(".value");
let yPos = 0;
const render = () => {
value.innerHTML = yPos;
//2 이미지의 스타일의 transform을 translateY로 이동시키게 하기
image.style.transform = `translateY(${-yPos}px)`;
//1 변화하는 변수 값
yPos++;
requestAnimationFrame(render);
};
render();
</script>
</body>
위에서 사용한 예시에 이미지 경로에 지정한 이미지를 가지고 raf를 이용해서 애니메이션을 만들려면
1. 변화하는 변수 값을 이미지의 y position 값으로 쓰고
2. 이미지 스타일의 transform을 translateY로 이동을 시켜볼게여 translateY안에 yPos
값 px만큼 움직일 수 있게 지정해준다.
이제 이렇게 되면 애니메이션이 아주 잘 작동을 하게 된다.
그치만 아직까진 can't stop ...
🔻멈추는 방법에 대해서 알아보자🔻
cancelAnimationFrame(requestAnimationFrame(callback));
//클릭하면 애니메이션 멈추게
<body>
<div class="container">
<img class="image" src="/이미지경로" />
<div class="value">requestAnimationFrame</div>
</div>
<script>
const image = document.querySelector(".image");
const value = document.querySelector(".value");
let yPos = 0;
//1
let rafId;
const render = () => {
value.innerHTML = yPos;
image.style.transform = `translateY(${-yPos}px)`;
yPos++;
//2
rafId = requestAnimationFrame(render);
};
render();
window.addEventListener("click", () => {
cancelAnimationFrame(rafId);
});
</script>
</body>
만약 여기서 rafId를 console에 찍으면 뭐가 나올까여
console.log(rafId);
//console창
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
.
.
100
.
.
.
♾️
그냥 1씩 늘어나면서 숫자가 찍힌다.
그래서 우리는 rafId가 숫자로 리턴이 된다는 걸 알 수가 있고 2번의 rafId 값을 이용해서 멈출 수가 있다.
어떻게 하냐하면 바로,
cancelAnimationFrame()
을 해주고 매개변수 자리에 인자로 rafId
를 넣어주면 된다.
그리고 클릭하면 애니메이션이 멈춘다..!
그럼 이제 나는 raf를 사용해봤다고 할 수 있겠다.