js dom, node 의 기초적인 활용

들어가며

  • js로 파싱되는 html의 객체들은 일종의 속성과 계층적 관계가 생긴다. 이러한 속성과 관계 전체를 js는 노드라고 한다.
  • document는 head와 body를 자식으로 하며, body는 div와 form 을 자식으로 하고, form 내부에는 input 과 h3 이 형제의 관계를 가진다. 이러한 element 의 계층적 관계와 각 각의 태그는 모두 노드이다. img는 src, width 를 속성으로 가지며 input은 value, title, type 등을 속성으로 가진다. 이러한 속성 attribute 역시 노드이다. 그 외 주석, 텍스트 등 html 을 이루는 모든 것이 노드이며, js 를 통해 출력하고 조작할 수 있는 대상이 된다.
  • 결국 dom을 조작한다는 것은 document의 node 를 이해하고 그것을 통제한다는 의미이다.

들어가기 전에, kebab-case 와 camelCase?

  • html은 kebab-case 를 사용하고 js는 camelCase를 사용한다.
  • node 는 그것의 이름을 기본적으로 js 의 네이밍 문법으로 번역된다. something.camelCase
  • html 스타일로 접근 가능하다. something.['kebab-case']
  • 어떤식으로 접근하든 상관 없지만, html 블럭에서는 kebab-case으로 명명해야 하며, js 블럭에서는 camelCase로 접근해야 한다. 그래서 아래와 다음과 같은 형태의 코드를 작성해야 한다.
    • <input type="button" class="btn-add">
    • var btnAdd = myForm.getElementsByClassName('btn-add')[0];

element node에 접근하기

getElementBy, querySelect

  • getElementBy___ 를 통하여 html의 element를 식별하는 속성이나 태그 이름 등으로 노드에 접근 가능하다.
    • id는 하나이므로 하나만 반환한다. class, name은 복수가 가능하므로 리스트를 반환하며 index로 값에 접근한다.
  • css 문법을 이용하는 querySelect를 요새는 주로 사용한다. querySelectAll로 접근할 경우 index로 추출한다.
// !html 생략

<section>
    <h4>EX1 :  getElementBy</h4>
    <input type="text" id="txt-x">
    +
    <input type="text" id="txt-y">
    <input type="button" id="btn-add" value="=">
    <input type="text" id="txt-sum">
    <hr>
</section>
<script>
    var txtX = document.getElementById('txt-x');
    var txtY = document.getElementById('txt-y');
    var btnAdd = document.getElementById('btn-add');
    var txtSum = document.getElementById('txt-sum');
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX.value, txtY.value);
    };            

    var adder = function(x, y){
        return parseInt(x) + parseInt(y);
    }
</script>

<section id="sec2">
    <h4>EX2 : element 선택 개선</h4>
    <input type="text">
    +
    <input type="text">
    <input type="button" class="btn-add" value="=">
    <input type="text">
    <hr>
</section>
<script>
    var sec2 = document.getElementById('sec2');
    var inputs = sec2.getElementsByTagName('input');
    var txtX = inputs[0];
    var txtY = inputs[1];
    var btnAdd = inputs[2];
    var txtSum = inputs[3];
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX, txtY);
    };            

    var adder = function(x, y){
        console.log(x, y)
        return parseInt(x.value) + parseInt(y.value);
    }
</script>

<section id="sec21">
    <h4>EX2-1 : element 선택 개선2</h4>
    <input type="text" class="txt-x">
    +
    <input type="text" class="txt-y">
    <input type="button" class="btn-add" value="=">
    <input type="text" class="txt-sum">
    <hr>
</section>
<script>
    var sec21 = document.getElementById('sec21');

    var txtX = sec21.getElementsByClassName('txt-x')[0];
    var txtY = sec21.getElementsByClassName('txt-y')[0];
    var btnAdd = sec21.getElementsByClassName('btn-add')[0];
    var txtSum = sec21.getElementsByClassName('txt-sum')[0];
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX, txtY);
    };            

    var adder = function(x, y){
        console.log(x, y)
        return parseInt(x.value) + parseInt(y.value);
    }
</script>

<section id="sec3">
    <h4>EX3 : selectors api level 1 </h4>
    <input type="text" class="txt-x">
    +
    <input type="text" class="txt-y">
    <input type="button" class="btn-add" value="=">
    <input type="text" name="txt-sum">
    <hr>
</section>
<script>
    var sec3 = document.querySelector('#sec3');

    var txtX = sec3.querySelector('.txt-x');
    var txtY = sec3.querySelectorAll('.txt-y')[0];
    var btnAdd = sec3.querySelector('.btn-add');
    var txtSum = sec3.querySelector('input[name="txt-sum"]');
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX, txtY);
    };            

    var adder = function(x, y){
        console.log(x, y)
        return parseInt(x.value) + parseInt(y.value);
    }
</script>

childNodes, children

  • 노드에 대하여 직접적으로 접근 가능하다.
    • childNodes를 통해 부모노드가 가진 모든 자식 노드에 접근한다.
    • children를 통해 부모노드가 가진 모든 element 자식 노드에 접근한다.
<section id="sec4">
    <h4>EX4 : childNode </h4>
    <input type="text" class="txt-x">
    +
    <input type="text" class="txt-y">
    <input type="button" class="btn-add" value="=">
    <input type="text" name="txt-sum">
    <hr>
</section>
<script>
    var sec4 = document.querySelector('#sec4');

    console.log("child nodes", sec4.childNodes); // element를 포함하여 문자열, 주석 등 모든 노드에 접근한다.

    var txtX = sec4.childNodes[3];
    var txtY = sec4.childNodes[5];
    var btnAdd = sec4.childNodes[7];
    var txtSum = sec4.childNodes[9];
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX, txtY);
    };            

    var adder = function(x, y){
        console.log(x, y)
        return parseInt(x.value) + parseInt(y.value);
    }
</script>

<section id="sec5">
    <h4>EX5 : children </h4>
    <input type="text" class="txt-x">
    +
    <input type="text" class="txt-y">
    <input type="button" class="btn-add" value="=">
    <input type="text" name="txt-sum">
    <hr>
</section>
<script>
    var sec5 = document.querySelector('#sec5');

    console.log("children", sec5.children); // children은 element만을 값으로 한다.

    var title = sec5.children[0];
    var txtX = sec5.children[1];
    var txtY = sec5.children[2];
    var btnAdd = sec5.children[3];
    var txtSum = sec5.children[4];
    
    btnAdd.onclick = function() {
        txtSum.value = adder(txtX, txtY);
    };            

    var adder = function(x, y){
        console.log(x, y)
        return parseInt(x.value) + parseInt(y.value);
    }
</script>

attr node 의 출력과 조작

  • element 에 접근하고 그것의 속성까지 조작할 수 있다.
  • datalist는 ES5에 나온 문법으로 select 과 유사하다.
  • style의 모든 값은 string이다. 그러므로 mySpan.style.fontSize="10px" 이런 식으로 해야한다.
<section id="sec6">
    <h4>EX6 : element node  대한 속성  CSS 스타일 변경 </h4>
    <input class="border-input" list="border-list">
    <datalist id="border-list">
        <option value="10px solid red">border1</option>
        <option value="3px dotted blue">border</option>
        <option value="30px dashed green">border</option>
    </datalist>

    <select id="img-select">
        <option value="/4169e1/ffffff?text=royalblue">img1</option>
        <option value="/008080/EEEEEE?text=teal">img2</option>
        <option value="/320x100/800080/EEEEEE?text=purple">img3</option>
    </select>   
    
    <input type="button" value="선택" class="btn-img">
    <hr>
    <img class="img">
    <hr>
</section>
<script>
    var sec6 = document.querySelector('#sec6');

    var img = sec6.querySelector(".img");
    var btnAdd = sec6.querySelector(".btn-img");
    var imgSelect = sec6.querySelector("#img-select");
    var borderInput = sec6.querySelector(".border-input");

    var acc = accrue();
    btnAdd.onclick = function() {
        img.src = "http://placehold.it/320x100" + imgSelect.value;
        img.style.border = borderInput.value;
        img.style.marginLeft = acc() + "px";
        img.style['margin-top'] = acc() + "px";
    };            

    function accrue(){
        var num = 10;
        return function (){
            num = num * 1.25 
            return num;
        }
    }
</script>

나아가며

  • function 이 리턴값이 될 수 있다는 사실만큼 받아드리기 어렵지만 가장 익숙하지만 파트가 바로 이번의 node 파트였다.
  • 단순하게 접근하면 좋을 것 같다. element에 접근하는 방법은 children, getElement, querySelect으로 접근하며, 접근한 객체에 대한 속성은 something.value, something.style.color 스트림처럼 접근한다.