✔ Element Node에 대한 정리

: element는 HTML에서 태그로 적은 노드들을 지칭하며 노드의 특정 타입을 말한다. (Node.Element Node)

: <html>, <div>, <title>과 같이 태그로 표현된 것들은 모두 element이나, 주석, text node와 같이 HTML태그로 표현된게 아닌 것은 element 가 아니다.

: JS DOM에서 Node는 Node의 Constructor이고,  HTML Element는 element의 Constructor이다.

예) sibling element에 접근하고 싶을때 parentElement로 접근해야지 parentNode로 접근하면 안된다.

 

 

DOM은 무엇인가? DOM Node와 Element의 차이

여행자보험의 보장명과 보장가격을 가져오기 위해 웹크롤링을 해보았다. 사실 이 과정은 그냥, html parsing해주는 라이브러리를 사용해서 html에서 내가 원하는 정보를 가져오는 것이 전부였다. 원

velog.io

 

 

[1] 텍스트 노드 추가/삭제 (document.createTextNode(), .appendChild())

 

1-1) 텍스트 노드 추가 순서

① 텍스트 노드 생성 var txt = document.createTextNode("안녕");

② 텍스트 노드를 추가할 엘리먼트 노드 선택 var div1 = document.getElementById("div1");

③ 엘리먼트 노드에 텍스트 노드 추가  div1.appendChild(txt); // txt는 div1의 자손이 된다

 

<section id="section6">
        <h1>Ex6: 노드조작: 메뉴추가 (createTextNode, Element) </h1>
        <div>
            <input class="title-input" name="title" />
            <input type="button" class="add-button" value="추가" />
            <input type="button" class="del-button" value="삭제" />
        </div>
        <ul class="menu-list">

        </ul>
    </section>
    --------------------------
    
// Ex6: 노드조작: 메뉴추가 (createTextNode, Element)
window.addEventListener("load",function(){
    var section = document.querySelector("#section6");
    
    var titleInput = section.querySelector(".title-input");
    var menuListUl = section.querySelector(".menu-list");
    var addButton = section.querySelector(".add-button");
    var delButton = section.querySelector(".del-button");

    addButton.onclick=function(){ // 단순히 텍스트를 가로로 붙이는게 아니라 리스트 화 시킴
        var title = titleInput.value;	// 입력값
        var txtNode = document.createTextNode(title); // 입력값의 노드화
        
        var aNode = document.createElement("a"); // <li><a href=""></a></li> 직접만들기
        aNode.href="";
        aNode.appendChild(txtNode);

        var liNode = document.createElement("li");
        liNode.appendChild(aNode);

        menuListUl.appendChild(liNode);

        /* var title = titleInput.value;
        var txtNode = document.createTextNode(title);  // 일반 문자열은 노드가 아니므로 노드화 시켜줘야 함
        menuListUl.appendChild(txtNode);*/ // 자식노드로 붙여서 추가되게 함

    };

    delButton.onclick=function(){
   	  	var txtNode = menuListUl.childNodes[0];
        menuListUl.removeChild(txtNode);
    };
    
});

 

 

1-2) 텍스트 노드에 엘리먼트 노드 추가/삭제 (append, innerHTML, remove)

// Ex6: 노드조작: 메뉴추가 (createTextNode, Element)
window.addEventListener("load",function(){
    var section = document.querySelector("#section6");
    
    var titleInput = section.querySelector(".title-input");
    var menuListUl = section.querySelector(".menu-list");
    var addButton = section.querySelector(".add-button");
    var delButton = section.querySelector(".del-button");

    addButton.onclick=function(){
        var title = titleInput.value; 

		//menuListUl.innerHTML='<a href="">'+ title + '</a>'를 아래와 같이 구조화 (노드 생성후 붙이기)
        var html = '<a href="">'+ title +'</a>'; 
        var li = document.createElement("li");
        li.innerHTML=html;

        menuListUl.append(li);
        //menuListUl.appendChild(li); 부모자식관계를 얻어야만 추가가능 
    };

    delButton.onclick=function(){
        var liNode = menuListUl.children[0]; // menuListUl의 자식만 확인
        //var txtNode = menuListUl.childNodes[0];  모든 자식노드의 [0]을 반영함
        
        liNode.remove();
        //menuListUl.removeChild(liNode); 
    };
    
});

 

 

[2] 노드복제와 템플릿

: html까지 다 가져오긴 너무 세세해서 js 자료만 정리

    var section = document.querySelector("#section7");
    
    var noticeList =section.querySelector(".notice-list"); 
    var tbodyNode = noticeList.querySelector("tbody");
    var cloneButton = section.querySelector(".clone-button");
    var templateButton = section.querySelector(".template-button");

    cloneButton.onclick = function(){
        var trNode = noticeList.querySelector("tbody tr")
        var cloneNode = trNode.cloneNode(true); // false 는 껍데기만, true는 자식노드까지 다 복제함

        var tds = cloneNode.querySelectorAll("td") // 복제한 각 노드의 내용 변경
        tds[0].textContent=notices[0].id;
        tds[1].innerHTML= '<a href="'+notices[0].id+'">' + notices[0].title + '</a>';
        tds[2].textContent=notices[0].regDate;
        tds[3].textContent=notices[0].writerId;
        tds[4].textContent=notices[0].hit;

        tbodyNode.append(cloneNode);
        
    };

    templateButton.onclick = function(){
        var template = section.querySelector("template");
        var cloneNode = document.importNode(template.content,true);
        var tds = cloneNode.querySelectorAll("td") // 복제한 각 노드의 내용 변경
        tds[0].textContent=notices[0].id;
        //tds[1].innerHTML= '<a href="'+notices[0].id+'">' + notices[0].title + '</a>';

        var aNode=tds[1].children[0]; // 위 문장의 구조화
        aNode.href=notices[0].id;
        aNode.textContent = notices[0].title;

        tds[2].textContent=notices[0].regDate;
        tds[3].textContent=notices[0].writerId;
        tds[4].textContent=notices[0].hit;

        tbodyNode.append(cloneNode);  // 복제할때 가장 첫줄만 복사됨

    };

});

 

 

[3] 노드삽입(insertBefore, insertAdjacentElement), 노드순회 (firstChild, previous

3-1) 노드객체 선택

readonly attribute Node parentNode;

readonly attribute Node firstChild;

readonly attribute Node lastChild;

readonly attribute Node previousSibling;

readonly attribute Node nextSibling;

* element만 대상으로 하고싶은 경우는 firstElementChild, lastElementChild, previousElemenetSibling, nextElementSibling을 사용

 

  <section id="section8">
        <h1>Ex8-노드 삽입과 바꾸기</h1>      // 게시글 줄바꾸기       
        <div>                
            <input type="button" class="up-button" value="위로" />                
            <input type="button" class="down-button" value="아래로" />
        </div>
        
------------------

//Ex8-노드 삽입과 바꾸기
window.addEventListener("load", function(){

    var section = document.querySelector("#section8");
    
    var noticeList =section.querySelector(".notice-list"); 
    var tbodyNode = noticeList.querySelector("tbody");
    var upButton = section.querySelector(".up-button");
    var downButton = section.querySelector(".down-button");

    var currentNode = tbodyNode.firstElementChild;//.children[0]; 선택된 tr노드

    downButton.onclick = function(){
        var nextElementNode = currentNode.nextElementSibling;

        if(nextElementNode==null){
            alert("더 이상 이동할 수 없습니다.");
            return;
        }

        tbodyNode.removeChild(nextElementNode); // nextNode를 참조하는 변수가 있으므로 화면에서만 안보이고 사라지는건 아님
        tbodyNode.insertBefore(nextElementNode,currentNode); // (옮길노드, 기준노드)

        
    };

    upButton.onclick = function(){
        var previousElementNode = currentNode.previousElementSibling;

        if(previousElementNode==null){
            alert("가장 앞에 있습니다");
            return;
        }

        tbodyNode.removeChild(currentNode); 
        tbodyNode.insertBefore(currentNode,previousElementNode);
        // insertBefore밖에 없으므로 현재 노드를 삭제해서 앞노드의 before로 올려야 한다
    };
});

* 자바스크립트 1회차라 노드 제어 들어가고나선 (어려움에) 진도가 안나가서 답답했는데... upButton은 혼자 성공해서 행복

** 사실 insertBefore자체가 옮겨주는거라 remove 없이도 똑같이 작동이 된다. 이해가 편하도록 remove를 넣었다고 하심..!

 

 

 

3-2) 노드  포지션의 원활한 이동 targetElement.insertAdjacentElement(position,element); // 타겟의 이웃한 곳에 삽입. 부모자식 관계가 아님!

'beforebegin': before the targetElement itself.

'afterbegin': just inside the targetElement, before its first child. 안쪽 컨텐트의 첫머리

'beforeend': just inside the targetElement, after its last child. 안쪽 컨텐트의 마지막

'afterend': After the targetElement itself.

 

//Ex8-노드 삽입과 바꾸기
// (위와 동일하여 생략)

    downButton.onclick = function(){
        var nextElementNode = currentNode.nextElementSibling;

        if(nextElementNode==null){
            alert("더 이상 이동할 수 없습니다.");
            return;
        }

        //tbodyNode.insertBefore(nextElementNode,currentNode);
        currentNode.insertAdjacentElement("beforebegin",nextElementNode);
        // 현재 노드 기준으로 생각했을떄 다음 노드가 내 앞으로 오게 설정
    };

    upButton.onclick = function(){
        var previousElementNode = currentNode.previousElementSibling;

        if(previousElementNode==null){
            alert("가장 앞에 있습니다");
            return;
        }
        //tbodyNode.insertBefore(currentNode,previousElementNode);
        currentNode.insertAdjacentElement("afterend",previousElementNode);
    };
});

 

[4] 다중엘리먼트 선택방법과 일괄 삭제

    <section id="section9">
        <h1>Ex9-다중 노드선택 방법과 일괄삭제, 노드의 자리바꾸기</h1>    
        <div>                
            <input type="button" class="del-button" value="일괄 삭제" />
            <input type="button" class="swap-button" value="선택된 노드 바꾸기" />
        </div>
        <table border="1" class="notice-list">
            <thead>
                <tr>
                    <td><input class="overall-checkbox" type="checkbox"></td>
                    <td>번호</td>
                    <td>제목</td>
                    <td>작성일</td>
                    <td>작성자</td>
                    <td>조회수</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><input type="checkbox"></td>
                    <td>1</td>
                    <td><a href="1">자바스크립트</a></td>
                    <td>2023-04-30</td>
                    <td>writer</td>
                    <td>2</td>
                </tr>
                
    --------------------
    
    //Ex9-다중 노드선택 방법과 일괄삭제, 노드의 자리바꾸기
window.addEventListener("load", function(){

    var section = document.querySelector("#section9");
    
    var noticeList =section.querySelector(".notice-list"); 
    var tbody = noticeList.querySelector("tbody");
    var allCheckbox = section.querySelector(".overall-checkbox");
    var delButton = section.querySelector(".del-button");
    var swapButton = section.querySelector(".swap-button");

    allCheckbox.onchange = function(){
        var inputs = tbody.querySelectorAll("input[type='checkbox']"); 
        for(var i=0; i<inputs.length; i++)
            inputs[i].checked=allCheckbox.checked; // 전체 선택 박스의 checked 타입을 개별 박스에 넣음
    };

    delButton.onclick = function(){
        var inputs = tbody.querySelectorAll("input[type='checkbox']:checked"); // 체크된 내용만 가져온다
        //console.log(inputs.length); 선택된 개수 추출
        //if(inputs[0].checked)
        
        for(var i=0; i<inputs.length; i++)
            inputs[i].parentElement.parentElement.remove(); // 텍스트의 조상td의 조상tr을 삭제
    };

 

 

[5] 두 엘리먼트의 자리바꾸기 replace with, cloneNode

: 두개 선택해서 자리바꾸기

: 세개 이상 선택하면 에러메세지가 나온다

swapButton.onclick = function(){
        var inputs = tbody.querySelectorAll("input[type='checkbox']:checked"); // 선택된것만 가져온다

        if(inputs.length !=2){ // 두개 이상 선택시 노티스 띄우기
            alert("두개만 선택해주세요");
            return;
        }
        
        var trs = [];
        for(var i =0; i<inputs.length; i++)
            trs.push(inputs[i].parentElement.parentElement);
        
        var cloneNode = trs[0].cloneNode(true); // 0번째의 복제본 만들기
        trs[1].replaceWith(cloneNode); // 복제본과 1번째를 교체
        trs[0].replaceWith(trs[1]); // 0번째와 1번째를 교체
    };
});

 

 

[6] 제목으로 내용 정렬

: [제목]을 눌렀을때 타이틀의 오름차순, 내림차순대로 정리되어 나타남

: html내 내용이 아니라 js쪽에 데이터바인드 된 (ajax) 내용을 기준으로 정렬함

    <section id="section10">
        <h1>Ex10-클릭한 컬럼을 기준으로 레코드 정렬하기 #1</h1>  
        <template>
            <tr>
                <td></td>
                <td><a href=""></a></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </template>
        <table border="1" class="notice-list">
            <thead>
                <tr>
                    <td class="id">번호</td>
                    <td class="title">제목</td>
                    <td class="reg-date">작성일</td>
                    <td class="writer-id">작성자</td>
                    <td class="hit">조회수</td>
                </tr>
            </thead>
            <tbody>
               //tbody내 내용은 없는거나 마찬가지므로 주석처리됨
            </tbody>
        </table>
    </section>
    <hr /> 
    
    -------------------------
    
    //Ex10-클릭한 컬럼을 기준으로 레코드 정렬하기 #1
window.addEventListener("load", function(){

    var notices = [
        {"id":1, "title":"데이터", "regDate":"2019-02-05", "writerId":"newlec", "hit":2},
        {"id":2, "title":"바인드", "regDate":"2019-02-02", "writerId":"newlec", "hit":0},
        {"id":3, "title":"리스트", "regDate":"2019-02-01", "writerId":"newlec", "hit":1},
        {"id":4, "title":"내용", "regDate":"2019-01-25", "writerId":"newlec", "hit":0}
    ];

    var section = document.querySelector("#section10");
    
    var noticeList =section.querySelector(".notice-list");
    var titldTd = section.querySelector(".title");
    var tbodyNode = noticeList.querySelector("tbody");

    var bindData = function(){ // 데이터 바인드 작업
        var template = section.querySelector("template");

        for(var i=0; i<notices.length; i++){ // 이전에 데이터 복사해왔던 코드
            var cloneNode = document.importNode(template.content, true);
            var tds = cloneNode.querySelectorAll("td");
            tds[0].textContent = notices[i].id;            

            var aNode = tds[1].children[0];
            aNode.href=notices[i].id;
            aNode.textContent = notices[i].title;

            tds[2].textContent = notices[i].regDate;
            tds[3].textContent = notices[i].writerId;
            tds[4].textContent = notices[i].hit;

            tbodyNode.appendChild(cloneNode);
        }
    };

    bindData();

    var titleSorted = false; // 정렬이 안된 상태

    titldTd.onclick = function(){ // 클릭시 notices배열 정렬 후 bindData() 재호출
        tbodyNode.innerHTML=""; // 기존 내용은 클리어처리
        
        if(!titleSorted)
            notices.sort(function(a,b){
                titleSorted=true; //정렬된 상태

                if(a.title < b.title)
                    return -1;
                else if(a.title > b.title)
                    return 1;
                else return 0;  
            });

        else
          notices.reverse(); // 기존의 레코드가 뒤집어짐.  if절은 한번 호출된 후에는 true상태이므로 reverse만 계속 호출되게 됨

        bindData();
    };
});

 

* sort레퍼런스 - 개체는 해당 속성 중 하나의 값을 기준으로 정렬할 수 있습니다.

 

Array.prototype.sort() - JavaScript | MDN

sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅니다.

developer.mozilla.org

 

 

 

+ Recent posts