본문 바로가기
CodeIt_Sprint/JavaScript_중급

(10)JavaScript중급_4_이벤트 활용_Mouse_event_2_마우스포인터

by 코잼민 2024. 11. 15.

#알아야 할 개념 :

● 개념_1 : Mouse 이벤트_2_마우스 포인터(움직이는 마우스) 관련 event

○ 정의 :Mouse 포인터에 관한 기본적인 event.type event.프로퍼티가 존재한다.

○ event.type : (5가지)

  • 마우스 포인터가 요소 내 움직일 때, event.type : 'mousemove'
  • 마우스 포인터가 요소 밖 => 안으로 움직일 때,  event.type : 'mouseover' || 'mouseenter'
  • 마우스 포인터가 요소 안 => 밖으로 움직일 때, event.type : 'mouseout' || 'mouseleave'

○ event.프로퍼티 :

  • 마우스 포인터가 요소기준 위치값 반환메소드 : offset(X||Y) 
  • 마우스 포인터가 웹페이지 기준 위치값 반환메소드 : page(X||Y) 
  • 마우스 포인터가 브라우저 창의 크기 기준 위치값 반환메소드 : client(X||Y) 
  • 마우스의 현재 포인터된 요소노드값을 반환 : relatedTarget

※참고로 X,Y는 각 기준점의 

  • X : 오른쪽으로 갈수록 값이 증가한다.
  • Y : 아래로 갈수록 값이 증가한다.

※ 활용 사례 : 마우스 포인터가 움직인 이동 방향을 client, page, offset 의 X,Y값으로 표현 가능 (★암기 X 이해 O)

  • ↗ : X값 증가 , Y값 감소
  • ↙ : X값 감소 , Y값 증가
  • ↖ : X값 감소 , Y값 감소
  • ↘ : X값 증가 , Y값 증가

● ★개념_2 : Mouse_커서이동 활용하기_1

○ Default 상황 :

부모 Box + 자식 Box 4개(cell 1, 2,3,4)

요구조건 :

  • cell1,2,3,4 중 하나에 마우스 포인터에 닿을 때, 투명도를 낮춰서 인식
  • cell1,2,3,4에서 마우스 포인터를 벗어날 때, 투명도를 다시 높여 원상복귀

핵심 해결과정 :

1_핸들러 function 작성 :

①. if(event.target.classList.contain('원래상태의 클래스')) //해당 마우스 포인터가 cell의 마우스 닿기 전 클래스인지를 확인

②. 있다고 하면, => e.target.classList.toggle('마우스포인터 가 있을 때, 투명도 낮추는 class css 적용')

2_ ★부모 Box에 addEventListener() 적용

- 부모Box요소노드.addEventListener('mounseover', 핸들러);

- 부모Box요소노드.addEventListener('mounseout', 핸들러);

주의해야할 점 2가지 :

  • 부모Box에 핸들러 적용할 때, mounseover, mounseover 두 type에 모두 추가 해야한다. //안그러면 마우스 포인터가 떠날시 원상복구가 안됨
  • 'mouseenter', 'mouseleave'로 하면 안됨 //저걸로 하게 되면, 부모Box내 자식 cell들은 인식을 안함

 

정답 :

   const box = document.querySelector('.box');
   
       //올려졌을 때, 효과 내기
    function printEventData(e) {
      if (e.target.classList.contains('boxes')) {
        e.target.classList.toggle('done');
      }
    }
    
    box.addEventListener('mouseover',printEventData );
    box.addEventListener('mouseout',printEventData );

● ★개념_3 : Mouse_커서이동 활용하기_2 : 요소마다의 이동 경로 추적용 코드

 핵심 해결과정 :

①. 핸들러 구현부 : event.target과 event.relatedTarget 값을 출력해보면,

  • event.target : 현시점의 마우스 포인터 위에 있는 요소노드 태그 출력
  • event.relatedTarget : 변화가 됐다면, 그 전시점의 마우스 포인터 위에있는 요소노드 태그 출력

②. 마찬가지로 , ★부모 Box에 addEventListener() 적용

- 부모Box요소노드.addEventListener('mounseover', 핸들러);

- 부모Box요소노드.addEventListener('mounseout', 핸들러);

   const box = document.querySelector('.box');
   
    function currentPosition(e){
      console.log(`----------------------------------------`);
      console.log('target : ');
      console.log(e.target);
      console.log('relatedTarget : ');
      console.log(e.relatedTarget);
      console.log(`----------------------------------------`);
    }
    
    box.addEventListener('mouseover',currentPosition );
    box.addEventListener('mouseout',currentPosition );

 개념_4 : mouseover || mouseout  VS mouseenter || mouseleave 의 차이

  • mouseover || mouseout : 버블링 단계가 일어남 => 부모 Box 내 자식 cell을 인식한다.
  • mouseenter || mouseleave : 버들링 단계가 일어나지 않음 => 부모 Box내 자식cell 인식 X

 

※연습문제  :

 문제 조건 :

실습 설명

얼마 전 월급이 오른 효준이는 큰맘 먹고 집을 이사했습니다. 비록 전셋집이지만 나름대로 만족스러운 집을 구했어요.

실습 창의 코드는 효준이가 장만한 새로운 집의 평면도를 HTML과 CSS로 구현한 코드입니다. 다만, 코드를 실행해보면 아직 각 공간이 어떤 공간인지는 표시되지 않았어요.

HTML 코드를 좀 더 자세히 살펴보니 몇몇 태그에 data-title 속성에 각 태그가 의미하는 공간이 어떤 공간인지 적혀있습니다.

data-title 속성과 자바스크립트를 활용해서 마우스 커서가 해당 태그 위로 올라가면 data-title 속성의 값이 나타나도록 코드를 완성해 주세요.

세부적인 조건은 다음과 같습니다.

1. showTitle 함수

  • ①. showTitle 함수가 호출되면 가장 먼저 조건문을 통해 이벤트 객체의 target 프로퍼티에 담긴 요소에 data-title 속성의 값을 가지고 있는지 확인합니다.
  • ②. 조건문이 true일 경우 span 태그 형태의 요소 노드를 생성합니다.
  • ③. 이 요소 노드는 'title'이라는 class 값을 가지고 있어야 합니다.
  • ④. 이 요소 노드의 내부에 target 프로퍼티에 담긴 요소의 data-title 속성에 담긴 값을 할당해 주세요.
  • ⑤. 이 요소 노드를 target 프로퍼티에 담긴 요소의 마지막 자식 요소 노드로 추가해 주세요.

2. removeTitle 함수

  • ①.  removeTitle 함수가 호출되면 가장 먼저 조건문을 통해 이벤트 객체의 target 프로퍼티에 담긴 요소에 data-title 속성의 값을 가지고 있는지 확인합니다.
  • ②. 조건문이 true일 경우 이벤트 객체의 target 프로퍼티에 담긴 요소의 가장 마지막 자식 요소를 제거해 주세요.

3. 이벤트 핸들러 등록하기

    • ①. 앞서 만든 두 이벤트 핸들러를 하나의 요소 노드에만 등록해도 각 태그에 이벤트가 동작하도록 해주세요.
    • ②.  이벤트 위임을 고려했을 때 어떤 요소 노드에 이벤트 핸들러를 등록하면 좋을지 대상 부분을 수정해 주세요.
    • ③.  이벤트 위임을 고려했을 때 각각 타입의 이벤트로 이벤트 핸들러를 등록하면 좋을지 타입 부분을 수정해 주세요.
    •  

○ 코드 :

<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="UTF-8">
  <title>효준이네 집</title>
  <link rel="stylesheet" href="4.css">
</head>

<body>
  <div class="map">
    <div class="balcony" data-title="발코니"></div>
    <div class="room">
      <div class="room-1" data-title="침실">
        <div class="door"></div>
        <div class="window">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
      </div>
      <div class="room-2" data-title="침실/거실">
        <div class="window">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
        <div class="window window-2">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
      </div>
    </div>
    <div class="other">
      <div class="bathroom" data-title="욕실">
        <div class="door"></div>
        <div class="bath"></div>
        <div class="bathroom-block">
          <div class="sink"></div>
          <div class="toilet"></div>
        </div>
      </div>
      <div class="utility-room" data-title="다용도실">
        <div class="door"></div>
      </div>
      <div class="entrance" data-title="현관/입구">
        <div class="door"></div>
        <div class="wall"></div>
      </div>
      <div class="kitchen" data-title="주방/식당">
        <div class="kitchen-block">
          <div class="kitchen-sink"></div>
          <div class="stoves">
            <div class="stove"></div>
            <div class="stove"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>
    
  </script>
</body>

</html>

알아야 할 개념 :

  • HTML 코드에서 각 방에 요소노드 안에 "data-title"이라는 속성과 속성값(방의 이름)을 이용함 => dataset프로퍼티로 풀어야함
  • 각 요소노드에 data-title 속성 존재여부 판단 : event.target.dataset.속성값명프로퍼티이용

=> if(event.target.dataset.title) {....}

  • 노드(태그)에 data-title 속성 추가하는 방법 

=> element.textContent = element.dataset.title

 

풀이과정 :

①. showTtile() : //마우스 포인터가 각 방을 가리킬 경우 => 그 방의 이름 출력 메소드

  • if조건문 + 요소노드.dataset.속성명 프로퍼티 로 event.target 요소노드에 dataset.속성명값이 있는지 확인
  • 있다면, 요소노드 생성 , dataset.속성명 프로퍼티 삽입 : element.textContent = 부모의 dataset.title값
  • 그 event.target노드의 자식노드에 삽입 : e.target.append(요소노드) //마지막 노드에 추가시킴

②. removeTtile() : //마우스 포인터가 벗어날 경우 => 그방의 이름 다시 사라지기

: showTtile()에서 span노드를 생성후, 그 해당노드의 자식에 추가하였다. => 그럼 반대로 그 자식 노드를 삭제하기

=> e.target.lastElementChild.remove()

③. . ②에 showTitle(), removeTitle() 메소드를 event에 적용

=> 제일 상위 부모Box.appendEventListener('mouseover',showTitle()); //이름 출력은 마우스 포인터가 방에 들어갈 때 이므로, 'mouseover' 에 해당

=> 제일 상위 부모Box.appendEventListener('mouseout',removeTitle()); //이름 출력은 마우스 포인터가 방에나갈때. 이므로, 'mouseout' 에 해당

 정답 :

<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="UTF-8">
  <title>효준이네 집</title>
  <link rel="stylesheet" href="4.css">
</head>

<body>
  <div class="map">
    <div class="balcony" data-title="발코니"></div>
    <div class="room">
      <div class="room-1" data-title="침실">
        <div class="door"></div>
        <div class="window">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
      </div>
      <div class="room-2" data-title="침실/거실">
        <div class="window">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
        <div class="window window-2">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </div>
      </div>
    </div>
    <div class="other">
      <div class="bathroom" data-title="욕실">
        <div class="door"></div>
        <div class="bath"></div>
        <div class="bathroom-block">
          <div class="sink"></div>
          <div class="toilet"></div>
        </div>
      </div>
      <div class="utility-room" data-title="다용도실">
        <div class="door"></div>
      </div>
      <div class="entrance" data-title="현관/입구">
        <div class="door"></div>
        <div class="wall"></div>
      </div>
      <div class="kitchen" data-title="주방/식당">
        <div class="kitchen-block">
          <div class="kitchen-sink"></div>
          <div class="stoves">
            <div class="stove"></div>
            <div class="stove"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>
    const map = document.querySelector('.map');

    //요소 안에 들어갈 시 , 방의 이름 출력 핸들러
    function showTitle(e){
      if(e.target.dataset.title)
      {
        const node = document.createElement('SPAN');
        node.classList.add('title');
        
        //속성과 속성값 추가법
        node.textContent = e.target.dataset.title;

        e.target.append(node);
      }
    }

      //요소 밖으로 포인터 나갌 시 , 방의 이름 출력 x 핸들러
    function removeTitle(e){
      if(e.target.dataset.title)
    {
      e.target.lastElementChild.remove();
    }
    }

    //각 핸들러를 동작 event에 따라 부모Box인 map에 적용
    map.addEventListener('mouseover',showTitle);
    map.addEventListener('mouseout',removeTitle);

  </script>
</body>

</html>