본문 바로가기

JavaScript

[JavaScript] 노드 보러 왔다가 클래스 속성 제어도 배우고 갑니다

728x90

 

노드 이동

 

부모 노드,  자식 노드 선택

 

기능 설명
childNodes 모든 자식 노드 선택 (단, 노드에 생략된 text도 포함)
children 모든 자식 노드 선택
parentElement 부모 노드 선택
nextElementSibling 다음 형제 노드 선택
previousElementSibling 이전 형제 노드 선택
firstChild 첫번째 자식 노드 선택
lastChild 마지막 자식 노드 선택

 


부모, 자식 노드 선택을 다음의 웹 화면을 기준으로 해보자!

 

Document
이동 번호 이름 내용 날짜
1 홍길자 안녕! 2019-01-01
2 이순신 반가워 2019-02-01
3 이순신 반가워 2019-02-01
4 이순신 반가워 2019-02-01
5 이순신 반가워 2019-02-01

 

✅ parentElement

 

<tbody class="table">
      <tr>
          <td><button onclick="down(this)">↓</button><button onclick="up(this)">↑</button></td>
          <td>1</td>
          <td>홍길자</td>
          <td>안녕!</td>
          <td>2019-01-01</td>
      </tr>
      <tr>
          <td><button onclick="down(this)">↓</button><button onclick="up(this)">↑</button></td>
          <td>2</td>
          <td>이순신</td>
          <td>반가워</td>
          <td>2019-02-01</td>
      </tr>

    ....중략

 

   <script>
    
    function down(x){

     // console.log(x);  //자신 태그
            
     // console.dir(x); // 현재 상태에서 사용할 수 있는 함수를 보여주는 사전
     console.log(x.parentNode); // 부모 태그 ( 공백이 있다면, 공백을 선택 )
                                //x는 버튼 태그를 받는 매개변수로 부모 도는 tr
     console.log(x.parentElement); // 부모 태그 ( 순수한 태그의 형태만 선택 )
     //순수한 태그만을 추출하는 parentElement를 사용하는 게 좋다
    
    }

    </script>

 

 

✅ nextElementSibling & previousElementSibling ( 형제 노드 )

 

  console.log(x.parentElement.nextElementSibling); // 태그의 부모 요소의 다음 형제 노드 출력 => <td>1</td>
  console.log(x.parentElement.nextElementSibling.nextElementSibling); // <td>홍길자</td>
  console.log(x.previousElementSibling); // 이전형제 => 현재 없음 : null

 

 

 ✅firstElementChild & lastElementChild & children ( 자식 노드 )

 

   console.log(x.parentElement.parentElement.firstElementChild); // tr기준 첫번쨰 자식 태그
   console.log(x.parentElement.parentElement.lastElementChild); // tr기준 마지막 자식 태그 
   console.log(x.parentElement.parentElement.children); // 모든 자식 태그  >> 배열로 출력
   console.log(x.parentElement.parentElement.children[2]); // 모든 자식 태그 중 3번째 태그(배열이라서 인덱스로 호출 가능)

 

 

 ✅ 노드 이동시키는 방법

  insertBefore ( 삽입 노드, 기준 노드 )  -  기준노드 앞에 삽입노드 추가

 

  ⭐ insertBefore은 부모태그를 기준으로 실행되기 때문에 부모태그를 반드시 얻어야 한다

 

 

⬇️ 아래로 이동시키기

 

 

  var current = x.parentElement.parentElement; // 버튼의 부모행 => tr
  var next = current.nextElementSibling;  // tr의 다음 형제 노드

  // 확실하지 않으면 콘솔창으로 출력해보기
  console.log(current); 
  console.log(next);
 
  if ( next == null ){  
  alert("마지막 행 입니다");
  return; //함수종료
  }

  //insertBefore는 동작시킬 부모태그를 얻는다
  var table = document.querySelector(".table");
  table.insertBefore(next, current); //current앞에 next를 넣는다

 

 

⬆️ 위로 이동시키기

 

 

  //up 바튼을 생성해보자
  function up(y){
    var current = y.parentElement.parentElement; //tr
    var previous = current.previousElementSibling; // tr 기준 이전 형제 노드

    if ( previous == null ){  
      alert("첫번째 행 입니다");
      return; //함수종료
    }

    console.log(current);
    console.log(previous);

    var table = document.querySelector(".table");
    table.insertBefore(current, previous);
  }

 


노드 삭제

 

<body>
    
    <button button="type" id="delOne">하나씩 삭제</button>
    <button button="type" id="del">일괄 삭제</button>
    <table>
        <thead>
            <th><input type="checkbox" class="allCheck"></th>
            <th>번호</th>
            <th>이름</th>
            <th>내용</th>
            <th>날짜</th>
        </thead>

        <tbody class="table">
        <tr>
            <td><input type="checkbox" class="check"></td>
            <td>1</td>
            <td>홍길자</td>
            <td>안녕!</td>
            <td>2019-01-01</td>
        </tr>
        <tr>
            <td><input type="checkbox" class="check"></td>
            <td>2</td>
            <td>김길자</td>
            <td>안녕!</td>
            <td>2019-01-01</td>
        </tr>
        <tr>
            <td><input type="checkbox" class="check"></td>
            <td>3</td>
            <td>이길자</td>
            <td>안녕!</td>
            <td>2019-01-01</td>
        </tr>
        <tr>
            <td><input type="checkbox" class="check"></td>
            <td>4</td>
            <td>고길자</td>
            <td>안녕!</td>
            <td>2019-01-01</td>
        </tr>

        </tbody>

 

removeChild ( ) - 자식 태그를 하나씩 삭제하기 

 

      //하나씩 삭제 removeChild
      var delOne = document.getElementById("delOne");
      delOne.onclick = function() {
      var table = document.querySelector(".table"); // tr의 부모요소

      console.log(table.firstElementChild); //첫번째 요소
      console.log(table.children[0]); //배열 => 첫번쨰 요소

      table.removeChild(table.firstElementChild);

      // table.removeChild();
      }

 

remove ( ) - 노드 자체를 모두 삭제

 

     //일괄삭제 remove
     var del = document.getElementById("del");
     del.onclick = function(){
     var table = document.querySelector(".table tr"); 
     var check = document.querySelectorAll(".check");//체크 박스 전부 가져오기

 
       if(confirm("정말 삭제하시겠습니까?") == false){
               return;
        }

        console.log(check);
        console.log(check.length);
        for ( var i = 0; i < check.length; i++ ){
             console.log(i);
              if(check[i].checked){
                check[i].parentElement.parentElement.remove(); //tr삭제
              }
           }
        }

 

 

그런데 말입니다..!  getElementByClassName으로 체크박스 태그를 가지고 오면 다음과 같은 문제가 발생한다

 

    var check = document.getElementsByClassName("check"); //체크 박스 전부 가져오기

 

 

일괄삭제를 했을 때, 2번 3번 모두 삭제되는 것이 아니라 하나씩 지워지는 현상이 발생한다.

이러한 현상은 왜 이러나는 것일까?

getElementByClassName, querySelector 모두 태그를 클래스 이름으로 지정했을 떄 가지고 올 수 있는데 말이다.

그건 getElementByClassName이 태그를 가지고 올 때 컬렉션으로 가지고 오는데, 이는 삭제할 때 문제가 발생할 수 있다.

컬렉션을 삭제하게 되면, 해당하는 요소가 지워지면서 다음의 요소가 지워진 요소 자리로 인덱스가 당겨지면서 요소도 당겨지기 때문이다 . 따라서 삭제할 때는 getElementByClassName보다는 querySelector를 사용하는 것이 좋다

 

 

그러면 이번에 전체 선택 기능을 만들어볼까나?

 

     // 전체 선택 vs 전체 삭제
      var allCheck = document.querySelector(".allCheck");
      var check = document.querySelectorAll(".check") ;//체크 박스 전부 가져오기

      allCheck.onclick = function(){
        if(allCheck.checked){
           for(var i = 0; i < check.length; i++ ){
              check[i].checked = true;
           }
        }else{
            for(var i = 0; i < check.length; i++ ){
               check[i].checked = false;
             }
          }
       }

 

 

 

전체 선택을 하기 위해서는 위의 사진에서 빨간색으로 표시한 부분에 해당하는 태그에 접근해야 한다

 

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

 

그래서 클래스 이름이 allCheck인 체크박스 태그를 가지고 와야 한다

 

 

   var check = document.querySelectorAll(".check"); //체크 박스 전부 가져오기

 

그리고 각각의 체크 박스가 모두 체크되어야 하기 때문에 즉, 반복문을 통해 checked 속성을 줘야 하기 때문에

각각의 체크박스에 해당하는 태그들도 가지고 와야 한다

 

 

   allCheck.onclick = function(){
     if(allCheck.checked){
        for(var i = 0; i < check.length; i++ ){
          check[i].checked = true;
      }

 

 

그런 다음 allCheck 태그가 클릭과 동시에 allCheck 태그가 checked속성이 true였을 때, 모든 태그들이 선택되어야 하기 때문에 반복문을 통해 checked 속성을 true로 만들어주면 된다 ( 모두 선택 )

 

 

 }else{
    for(var i = 0; i < check.length; i++ ){
       check[i].checked = false;
     }
  }
}

 

태그가 checked 속성이 false 였을 때는 모든 태그들이 false가 될 수 있도록 조건을 설정해주었다 ( 선택 모두 해제 )

 

 

 

클래스 속성 제어하기

   클래스 속성 제어하는 대표적인 함수들

     1️⃣  add ( ) 

     2️⃣  remove ( )

     3️⃣  contains ( )

     4️⃣  toggle ( )

 

 

className & classList 

  ✅ className - 클래스명

  ✅ classList - 클래스명을 배열로 얻을 수 있음

 

 <button id="btn" class="btn btn-default">버튼</button>

    <script>
        var btn = document.getElementById("btn");
        btn.onclick = function(){

            //태그에 속성변경-->
            //console.log(btn.class);  //클래스는 키워드라 안 됨
            // console.dir(btn);

            console.log(btn.className); //클래스명을 얻음
            console.log(btn.classList); //클래스명을 배열로 얻음
        }
    </script>

 

cosole.log ( btn.className );

 

console.log ( btn.classList );

 

 

1️⃣ add ( )

    btn.classList.add("newBtn"); //클래스명 추가

 

 

2️⃣ remove ( )

 btn.classList.remove("btn-default"); //클래스명 삭제

 

 

 

3️⃣ contains ( )

     if(btn.classList.contains("btn")){
        console.log("btn클래스 존재함");
     }

 

클래스명에 "btn"이 존재하는지(포함되어 있는지)에 따라 결과값을 다르게 출력하도록 조건문을 설정하였다

 

 

4️⃣ toggle ( ) 

   toggle( )의 기능은 하나의 기능을 on/off 모두 할 수 있게끔 즉, 하나의 태그로 두 가지의 기능을 할 수 있게끔 해준다

 

     btn.classList.toggle("aaa"); //있으면 제거, 없으면 추가

 

  btn(버튼) 태그의 classList(클래스명)에 "aaa"가 없으면 추가

 

  btn(버튼) 태그의 classList(클래스명)에 "aaa"가 있으면 제거

 

 

좀 더 자세하게 토글의 기능에 대해 알아볼까?

 

👩‍💻 토글의 기능을 직관적으로 확인하기 위해 직접 기능을 작성

 

    <hr>
    <h3>하나의 버튼으로 두가지 작업을 처리하기(toggle)</h3>
    <button class="toggle" id="toggle">토글버튼</button> 
    <!-- id는 고유하기 때문에 식별하기 용이 => 이벤트 걸어주기 -->

  <script>
  
     var toggle = document.getElementById("toggle");
     toggle.onclick = function(){
       //토글의 기능 직접 작성
       if(toggle.classList.contains("add")){ //add가 포함되어 있다면
         toggle.style.color = "black"; //색상 변경
         toggle.classList.remove("add"); //클래스 제거
       } else {
         toggle.style.color="blue";
         toggle.classList.add("add");
       }
    }
    
   </script>

 

default값  -  폰트 색깔 : 검정,  클래스명 : toggle

 

"add"가 포함되어 있다면, 폰트 색깔은 검정으로 하고 classList에서 "add"는 지워줘

 

 

"add"가 포함되어 있지 않다면, 폰트 색깔은 파란색으로 바꾸고 classList에 "add"를 추가해

 

 

👩‍💻 똑같은 기능을 토글을 사용해서 구현

 

    toggle.onclick = function(){
       toggle.classList.toggle("add");
       console.log(toggle);
    }

 


실습을 통해 클래스 속성을 제어해보자! 그럼 이해가 잘 될 거야!

< style > 

  <title>Document</title>

    
    <style type="text/css">
        .center {
            text-align: center;
        }
        .content {
            overflow: hidden;
            border: 1px solid #777;
        }
        .content,
        .content .left,
        .content .right {
            width: 50%;
            margin: 0 auto;
            box-sizing: border-box;
            padding: 5px;
        }
        .content .right,
        .content .left {
            float:left;
        }
        .left .inner,
        .right .inner {
            border: 1px solid #777;
            height: 300px;
        }
        img {
            width: 100%;
            height: 100%;
        }
        
    </style>

</head>

 

 

< 태그 >

<body>

    <header>
        <div class="center">
            <h2>토글형태 활용하기</h2>
            <button id="btn1" class="dark">어둡게보기</button>
            <button id="btn2" class="name">이름보기</button>

            <!--추가-->
            <hr>
        </div>
    </header>
    
    <section>
        <div class="content">
            <div class="left">
                <div class="inner"><img src="profile.png"></div>
            </div>
            <div class="right">
                <div class="inner">
                    <p class="info" style="display:none;">홍길자<br>20세<br>능력단위<br>Java, Oracle, JSP, CSS, Javascript</p>
                    <p class="dict">자바스크립트는 객체 기반의 스크립트 프로그래밍 언어이다. 이 언어는 웹 브라우저 내에서 주로 사용하며, 다른 응용 프로그램의 내장 객체에도 접근할 수 있는 기능을 가지고 있다. 또한 Node.js와 같은 런타임 환경과 같이 서버 사이드 네트워크 프로그래밍에도 사용되고 있다</p>
                    <a href="https://www.naver.com">위키백과</a>
                </div>
            </div>            
        </div>
    </section>

 

 

< script >

  <script>
        //body 얻는 법
        //1. var body = document.querySelector("body");
        //2. var body = document.body;
        
        var body = document.body;
        var all = document.querySelectorAll("p, a, h2");

        var btn1 = document.getElementById("btn1");
        btn1.onclick = function(){
            //x클래스
            if(btn1.classList.contains("x")){
                btn1.innerHTML = "어둡게보기";   // 버튼 
                body.style.backgroundColor = "white"; // 배경 색상
                for(var i = 0; i < all.length; i++){  // 폰트 색상
                    all[i].style.color = "black";
                }
                btn1.classList.remove("x");
            }else{ 
                btn1.innerHTML = "밝게보기";   // 버튼 
                body.style.backgroundColor = "black"; // 배경 색상
                for(var i = 0; i < all.length; i++){  // 폰트 색상
                    all[i].style.color = "white";
                }
                btn1.classList.add("x");
                
            }
        }

        var btn2 = document.getElementById("btn2");
        var info = document.querySelector(".info");
        var dict = document.querySelector(".dict");

        btn2.onclick = function(){

            if(btn2.classList.contains("x")){
                btn2.classList.remove("x"); //클래스명 삭제
                btn2.innerHTML = "내용보기";
                info.style.display="none";
                dict.style.display = "block";
                
            }else{
                btn2.classList.add("x"); //클래스명 추가
                btn2.innerHTML = "이름보기";
                info.style.display="block";
                dict.style.display = "none";
            }

        }
    </script>

 


 

위의 실습 코드를 자세하게 뜯어보자면...

 

 

 

btn1(밝게 보기)를 클릭했을 때, 함수 실행

    btn1.onclick = function(){
     //x클래스
     if(btn1.classList.contains("x")){
        btn1.innerHTML = "어둡게보기";   // 버튼 
        body.style.backgroundColor = "white"; // 배경 색상

 

"밝게 보기"에 대한 기능이 실행해야 하기 때문에 누름과 동시에 버튼 태그의 사잇값은 "어둡게 보기"로 바꿔야 한다

그리고 웹 페이지의 색상을 하얀 색으로 바꿔야 하기 때문에 body태그를 가지고 와서 body의 스타일 속성의 backgroundColor를 white로 바꿔준다

 

 

✅ body는 다음과 같이 2가지 방법으로 불러올 수 있다

    //body 얻는 법
    1. var body = document.querySelector("body");
    2. var body = document.body;

 

 

 

그런 다음 폰트의 색상을 black으로 바꿔주려고 한다

    var all = document.querySelectorAll("p, a, h2");

    for(var i = 0; i < all.length; i++){  // 폰트 색상
         all[i].style.color = "black";
     }

 

그런데 폰트을 색상을 바꿔주려고 하다보니 글이 모두 다른 태그에 담겨 있어서 모든 태그를 불러와야 하는 문제가

발생했다. 물론 모든 태그를 각각 불러와서 폰트의 색상을 바꿀 수 있지만 위의 코드처럼 한 번에 불러서 바꿔줄 수 있다.

배열로 불러오기 때문에 반복문을 돌려 색상을 바꿔주면 된다.

 

 

  btn1.classList.remove("x");

 

이제 모두 바꾸었으면, "x"를 지워서 해당 버튼이 "어둡게 보기" 기능을 할 수 있도록 만들어준다

 

 

 

이제 반대의 경우도 똑같이 작성해주면 된다

 

btn1(어둡게 보기)를 눌렀을 때, 함수 실행

    }else{ 
         btn1.innerHTML = "밝게보기";   // 버튼 
         body.style.backgroundColor = "black"; // 배경 색상
         for(var i = 0; i < all.length; i++){  // 폰트 색상
            all[i].style.color = "white";
         }
          btn1.classList.add("x");          
       }
     }

 

위에서처럼 ( btn1 클래스명에 "x"가 포함되어 있지 않아야 한다 ) btn1(어둡게 보기)기능을 함과 동시에 btn1의

사잇값은 "밝게 보기"로 바뀌어야 하고 body 태그의 style 속성에서 배경 색상은 black으로 바꿔주고 폰트의 색상도 white로 바꾸어준다.

일련의 과정이 모두 끝나고 나면 "밝게 보기"의 기능을 할 수 있도록 btn1의 클래스명에 "x"를 추가해준다.

 


 

이제 다음 기능도 똑같은 방법으로 진행하면 된다

     var btn2 = document.getElementById("btn2");
     var info = document.querySelector(".info");
     var dict = document.querySelector(".dict");

     btn2.onclick = function(){

       if(btn2.classList.contains("x")){
          btn2.classList.remove("x"); //클래스명 삭제
          btn2.innerHTML = "내용보기";
          info.style.display="none";
          dict.style.display = "block";
                
        }else{
          btn2.classList.add("x"); //클래스명 추가
          btn2.innerHTML = "이름보기";
          info.style.display="block";
          dict.style.display = "none";
        }
     }

 

단 위의 기능의 경우 스타일 속성의 display을 사용해 글의 내용을 보이게 했다가 안 보이게 했다가 해야 한다는 점에 차이점이 있지만 이 또한 한 번 알면 쉽게 할 수 있다!

 

해당 태그를 안 보이게 하고 싶다면,  해당 태그.style.display = "none";
해당 태그를 보이게 하고 싶다면,  해당 태그.style.display = "block";