[javascript] resource가 load 되었을 때, 정확한 정보를 불러올 수 있다

*드림코딩 브라우저 101 실습6

코드

.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Coordinates</title>
    <script src="main.js" defer></script>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class='line horizon'></div>
    <div class='line vertical'></div>
    <img src="./img/target.png" alt="taget" class='target'>
    <span class='tag'></span>
  </body>
</html>

.css

body {
  background-color: black;
  margin: 0;
}

.line {
  position: absolute;
  background-color: white;
}
.horizon {
  width: 100%;
  height: 1px;
}

.vertical {
  height: 100%;
  width: 1px;
}

.target {
  position: absolute;
  transform: translate(-50%, -50%); /*요소의 절반만큼 x에서 이동, 요소의 높이만큼 50% 이동*/
}

.tag {
  color: white;
  position: absolute;
  transform: translate(20px, 20px);
  font-size: 38px;
  margin: 20px;
}

.js

const vertical = document.querySelector('.vertical');
const horizon = document.querySelector('.horizon');
const target = document.querySelector('.target');
const tag = document.querySelector('.tag');

const targetRect = target.getBoundingClientRect();
const targetHalfWidth = targetRect.width / 2;
const targetHalfHeight = targetRect.height / 2;

document.addEventListener('mousemove', (event) => {
  console.log(targetRect);
  const mouseX = event.clientX; 
  const mouseY = event.clientY;
  /*left, top은 성능 안좋음. translate를 사용하자!*/
  vertical.style.transform = `translateX(${mouseX}px)`; //style지정할 때는 px 붙혀줘야함
  horizon.style.transform = `translateY(${mouseY}px)`;
  target.style.transform = `translate(${mouseX - targetHalfWidth}px, ${mouseY - targetHalfHeight}px)`;
  tag.style.transform = `translate(${mouseX}px, ${mouseY}px)`;
  tag.innerHTML = `${mouseX}px, ${mouseY}px`;
});

문제 상황

target.style.transform = `translate(${mouseX - targetHalfWidth}px, ${mouseY - targetHalfHeight}px)`; 코드가 제대로 적용이 되지 않음.
targetRect 변수를 선언 및 할당해줄 때, 즉 const targetRect = target.getBoundingClientRect();를 했을 때 target의 이미지가 로딩이 되지 않아서 코드가 제대로 실행되지 않는 것이다. (리소스가 준비되지 않음)
실제로 테스트를 위해 console.log(targetRect);를 했을 때, DOMRect의 width, height가 0으로 나왔다.


문제 해결

const vertical = document.querySelector('.vertical');
const horizon = document.querySelector('.horizon');
const target = document.querySelector('.target');
const tag = document.querySelector('.tag');

//이미지, 리소스가 다 준비가 된 상태에서 아래 실행해야 정확한 target의 크기를 받을 수 있다. (load상태)
addEventListener('load', () => {
  const targetRect = target.getBoundingClientRect();
  const targetHalfWidth = targetRect.width / 2;
  const targetHalfHeight = targetRect.height / 2;

  document.addEventListener('mousemove', (event) => {
    const mouseX = event.clientX; 
    const mouseY = event.clientY;
    /*left, top은 성능 안좋음. translate를 사용하자!*/
    vertical.style.transform = `translateX(${mouseX}px)`; //style지정할 때는 px 붙혀줘야함
    horizon.style.transform = `translateY(${mouseY}px)`;
    target.style.transform = `translate(${mouseX - targetHalfWidth}px, ${mouseY - targetHalfHeight}px)`;
    tag.style.transform = `translate(${mouseX}px, ${mouseY}px)`;
    tag.innerHTML = `${mouseX}px, ${mouseY}px`;
  });
});

따라서, targetRect는 리소스가 다 load된 상태, 즉 모두 다운받아 진 후에 실행되어야 한다. 그래야 정확한 target.getBoundingClientRect()의 값을 가져올 수 있다.
추가적으로 addEventListener를 넣지 않고, target.style.transform = `translate(${mouseX - target.getBoundingClientRect().width / 2}px, ${mouseY - target.getBoundingClientRect().height / 2}px)`; 와 같이 풀어서 작성하면 제대로 작동했는데, 이는 target.style.transform 코드를 실행할 때는 target resource가 준비되었기 때문에 제대로 동작하는 것이다. 이와 같은 문제가 생기면 addEventListener을 사용하자!

좋은 웹페이지 즐겨찾기