jineecode

EVENT 본문

JS

EVENT

지니코딩 2020. 11. 26. 23:34

1. id=main-title의 배경색을 파란색으로 바꿀 것임.

 

<style>
      h1 {
        background: #fff000;
      }
</style>

<body>
  <body>
    <h1 id="main-title">event</h1>
    <ul class="ilbuni-mom">
      <li class="ilbuni">
        <img src="#" />
        <a class="link-google" href="http:google.com">google</a>
      </li>
      <li class="ilbuni">
        <img src="#" />
      </li>
      <li class="ilbuni">
        <img src="#" />
      </li>
    </ul>

    <button class="btn">클릭하세요</button>
    <script>
      //버튼을 클릭하면 바꾼다 그러면 js로 버튼을 가져와야함

      var btn = document.querySelector('.btn')
      console.log(btn)
    </script>
  </body>

event는 어떤 사건이며, 버튼을 클릭하면 이벤트가 발생하며 어떤 동작이 일어남.

 

 

2. 버튼을 클릭하면 바꿔야하므로 일단 js로 버튼을 가져와야 함.

   <script>
      var btn = document.querySelector('.btn')
      console.log(btn)
    </script>

결과 : <button class="btn">클릭하세요</button>

 

 

3. 버튼을 클릭하면 이벤트 배경색을 파란색으로 바꾼다는 것은 동작을 수행한다는 것이며 어떤 기능임. 즉 함수를 만들어야 함

 

미리 함수를 만들어 놨다가 버튼을 누르면 호출시키도록 코드를 짜야함.

 

바꿀 부분이 id=main-title 이므로, mainTitle도 가져옴.

 

    <script>
    
      var btn = document.querySelector('.btn')
      var mainTitle = document.querySelector('#main-title');

      function btnClickHandler() {
        
      }

 

4.배경색을 바꾼다는 것은 css를 바꾼다는 것. 

background : blue 로 해서 css를 추가해서 그 클래스를 넣어도 되고,

js에서 직접 css를 조작할 수도 있음.

 

js에서 css를 조작할 때 style이라는 객체가 관장함.

 

   <script>

      var btn = document.querySelector('.btn')
      var mainTitle = document.querySelector('#main-title');

      function btnClickHandler() {
        mainTitle.style.background = 'dodgerblue';
      }
    </script>

 

 

5.이제 버튼과 함수를 연결시키자.

btn.addEventListener('click',btnClickHandler);

결과

 

물론 on~ 을 써도 같은 결과가 나온다

 

btn.onclick = btnClickHandler;

 

 


 

 

1. 기본 메뉴 만들기: 여러개 중 1개만 활성화 하기

 

.menu-active {
        background: orange;
      }

우리가 클릭하게 될 때 css에 이 클래스를 설정해, 그 아이만 오렌지색으로 바뀌게 하기.

 

<h1 id="main-title">event</h1>
    <nav class="menu">
      <a href="#" class="menu-link" data-menu="1">menu 1</a>
      <a href="#" class="menu-link menu-active" data-menu="2">menu 2</a>
      <a href="#" class="menu-link" data-menu="3">menu 3</a>
    </nav>

menu2를 클릭했을 때 위와 같이menu-active 클래스가 들어가도록 만드는 게 목적.

 

 

 

2. menu-link들을 js로 가져온다.

<body>
    <h1 id="main-title">event</h1>
    <nav class="menu">
      <a href="#" class="menu-link" data-menu="1">menu 1</a>
      <a href="#" class="menu-link" data-menu="2">menu 2</a>
      <a href="#" class="menu-link" data-menu="3">menu 3</a>
    </nav>
    <script>
      var menulinks = document.querySelectorAll('.menu-link');
    </script>
  </body>

 

3. 3개 모두에게 클릭을 걸어줘야 함. 반복문 사용.

 

  <script>
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        console.log("click");
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

 

확인하면 "click"이 콘솔창에 찍힌다. (잘 작동함)

 

 

 

4. 이제 클릭하면 색이 들어오게 해보자

<script>
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        this.classList.add("menu-active");
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

this.classList.add("menu-active");

this를 써서 내가 클릭하는 '요소'에 클래스 'menu-active'를 넣어 색이 들어오게 한다.

this가 가리키는 대상, addEventListener를 호출한 객체 menuLinks[i] 이다.

이 코드의 문제는 다른 것을 클릭했을 때 처음에 클릭한 것의 색이 원래대로 돌아오지 않는다는 점에 있다.

 

 

5. 위의 문제를 해결할 수 있는 방법은 여러가지이다.

오렌지색 menu를 다시 파랗게 돌리는 것도 클릭 이벤트이다.

그러므로,

 function clickMenuHandler() 

함수에 같이 넣어주면 동작하겠다.

 

 

5-1 전체를 없애고 다시 오렌지로 바꾼다.

 

 <script>
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        for (var i = 0; i < menuLinks.length; i++) {
          menuLinks[i].classList.remove("menu-active");
        }
        this.classList.add("menu-active");
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

menu.classList.remove("menu-active")

 

'menu-active' class를 모두 지워주고, 필요한 것에 오렌지로 바꾼다.

 

이 코드의 문제는 우리는 간단한 동작이 필요한데 for문을 돌아야하는 비효율적인 코드이다.

 

 

5-2 menu-active를 찾아서 지운다.

 

  <script>
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        var activeMenu = document.querySelector(".menu-active");
        activeMenu.classList.remove("menu-active");
        this.classList.add("menu-active");
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

이 코드에 에러(Uncaught TypeError: Cannot read property 'classList' of null
    at HTMLAnchorElement.clickMenuHandler)가 뜨는 이유:

처음에는 당연히 menu-active가 들어있는 class가 없다 (클릭 이벤트가 전혀 발생되지 않음)

 

조건문을 사용해주어야 함.

 

 <script>
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        var activeMenu = document.querySelector(".menu-active");

        if (activeMenu) {
          activeMenu.classList.remove("menu-active");
        }
        this.classList.add("menu-active");
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

변수명 activeMenu가 true면 menu-active를 제거하고,

false면 menu-active를 추가해주세요.

 

이 코드의 단점 역시 속도 문제가 있다.

DOM 자체가 문서를 모두 뒤져야 하기 때문임. (연산 처리)

queryselector은 DOM을 써야하기 때문에 또 범용성이 없다.

 

 

5-3. 전역변수를 하나 만드는 방법.

<script>
      var currentMenu;
      var menuLinks = document.querySelectorAll(".menu-link");
      function clickMenuHandler() {
        if (currentMenu) {
          currentMenu.classList.remove("menu-active");
        }

        this.classList.add("menu-active");
        currentMenu = this;
      }

      for (var i = 0; i < menuLinks.length; i++) {
        menuLinks[i].addEventListener("click", clickMenuHandler);
      }
    </script>

 

전역변수 하나를 만든다. (var currentMenu;)

이것은 현재 활성화된 메뉴를 담을 변수 (기억공간).


클릭했을 때 그 값을 currentMenu 변수에 담아놨다가 담은 변수를 classList.remove 하여 비활성화 해주고 클릭한 this를 활성화한다

 

이렇게 하면 모든 문서를 뒤져볼 필요없이 currentMenu만 찾아서 처리해주면 된다.

 

이 코드의 단점은 for 문이 있기 때문에 연산의 효율이 떨어진다.

또한 addEventListener이 많을수록 성능 저하가 된다.

 

이를 해결하는 방법은 이벤트 위임이 있다.

 

 

5-4. 이벤트 위임.

menu-link의 부모, menu에게 이벤트를 시킨다.

 

    <style>
      .btn {
        font-size: 2rem;
      }

      .menu {
        display: flex;
      }

      .menu-link {
        margin: 0.5em;
        padding: 0.5em;
        color: #fff;
        text-decoration: none;
        background: dodgerblue;
        list-style: none;
      }

      .menu-active {
        background: orange;
      }

      .menu {
        background: yellowgreen;
      }
      
    </style>
  </head>

  <body>
    <h1 id="main-title">event</h1>
    <nav class="menu">
      <a href="#" class="menu-link" data-menu="1">menu 1</a>
      <a href="#" class="menu-link" data-menu="2">menu 2</a>
      <a href="#" class="menu-link" data-menu="3">menu 3</a>
    </nav>

    <script>
      var menu = document.querySelector(".menu");
      function clickHandler() {
        console.log(this);
      }
      
      menu.addEventListener("click", clickHandler);
    </script>

var menu = document.querySelector(".menu");

변수 menu를 가져온다 (DOM)

 

menu.addEventListener("click"clickHandler);

부모인 menu에게 click이벤트를 준다.

이때, 매개변수 두번째 자리에 clickHandler 라는 함수를 만든다.

 

 function clickHandler() {

        console.log(this);

      }

 

콘솔을 찍어본다. (클릭이벤트 잘 되는지 실행)

 

 

잘 가져왔음.

 

여기서 this는 addEventListener의 menu가 찍힘

 

 

5-5.

 

   <script>
      var menu = document.querySelector(".menu");
      function clickHandler(e) {
        console.log(e);
      }
      menu.addEventListener("click", clickHandler);
    </script>

clickHandler 앞에 e 는 뭘까?

 

clickHandler 함수가 addEventListener로서 실행이 되면, 첫번째 자리에 event 객체라는 특별한 객체가 들어옴. 그것이 바로 매개변수 e 임.

 

이것을 찍어보면,

 

수많은 클릭 이벤트 객체가 나열되어서 들어옴.

 

이 수많은 이벤트 객체 중 하나를 찍어보자

console.log(e.currentTarget);

  <script>
      var menu = document.querySelector(".menu");
      function clickHandler(e) {
        console.log(e.currentTarget);
      }
      menu.addEventListener("click", clickHandler);
    </script>

 

 

이것은 this와 같은 결과이다.

 

    <script>
      var menu = document.querySelector(".menu");
      function clickHandler(e) {
        console.log(this == e.currentTarget);
      }
      menu.addEventListener("click", clickHandler);
    </script>

 

true 가 나옴

 

 

    <script>
      var menu = document.querySelector(".menu");
      function clickHandler(e) {
        console.log(e.target);
      }
      menu.addEventListener("click", clickHandler);
    </script>

결과:

부모를 가리키지 않는다.

 

진짜 내가 누른 타겟을 가져옴.

 

이것이 바로 이벤트 위임이다.

 

 

반복문을 쓰지 않은 가장 이상적인 코딩이다.

   <script>
      var currentMenu;
      var menu = document.querySelector(".menu");
      function clickHandler(e) {
        if (currentMenu) {
          currentMenu.classList.remove("menu-active");
        }
        e.target.classList.add("menu-active");
        currentMenu = e.target;
      }

      menu.addEventListener("click", clickHandler);
    </script>

 

 

리팩토링

 <script>
      var currentMenu;
      var menu = document.querySelector(".menu");

      function activate(elem){
        elem.classList.add("menu-active");
        currentMenu = elem;
      }

      function inactivate(elem){
        currentMenu.classList.remove("menu-active");
      }

      function clickHandler(e) {
        if (currentMenu) {
          inactivate(currentMenu);
        }
        activate(e.target);
      }

      menu.addEventListener("click", clickHandler);
    </script>

 

이 코드의 장점은 따로 activate를 호출해놨기 때문에

사이트에 들어갔을 때부터 nav를 열어둘 수 있다.

 

   <script>
      var currentMenu;
      var menu = document.querySelector(".menu");

      function activate(elem){
        elem.classList.add("menu-active");
        currentMenu = elem;
      }

      function inactivate(elem){
        currentMenu.classList.remove("menu-active");
      }

      function clickHandler(e) {
        if (currentMenu) {
          inactivate(currentMenu);
        }
        activate(e.target);
      }

      menu.addEventListener("click", clickHandler);
      activate(document.querySelectorAll('.menu-link')[0]);
    </script>

 

'JS' 카테고리의 다른 글

지역 선택 JS로 제어하기  (2) 2021.02.26
이벤트 위임  (0) 2021.02.25
깨알 기초 지식 모음  (0) 2021.02.14
끝말잇기 만들기  (0) 2020.12.08
DOM 스크립트  (0) 2020.11.25
Comments