계속되는 축구중계에 약속으로 리듬이 많이 망가져있습니다.
어제는 그래도 저녁약속 이후에 블로그 쓰고, 바로 잘 수 있었습니다.
오늘도 아시안컵 준결승이 있으니 또 늦잠 자겠네요. 강의때 정신차려야 하는데..
오전에는 HTML/CSS 과제 만드는 것을 강사님이 직접 보여주셨습니다.
참고할 만한 과제였습니다. 만드는 과정을 처음부터 보니 흐름을 느낄 수 있었습니다.
특히 padding 이나 margin 주는 방법이 궁금했는데 일단 뼈대 다 잡아놓고, 부모 요소 기준으로 잡더라고요.
어떤 느낌인지는 알 것 같은데 사용할 수 있을지 모르겠습니다.^^ 늘 그렇죠ㅎㅎ
오늘 배운 DOM 정리해보겠습니다.


DOM(Document Object Model)

DDMHTML 문서의 내용을 트리형태로 구조화하여 웹페이지와 프로그래밍 언어를 연결시켜주는 역할을 합니다.
이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 노드(node) 라고 합니다.
요소, 속성, 콘텐츠를 다 노드 형태로 나눠서 다룰 수 있습니다. 여기까지만 들어도 HTML 문서 요소들을
모두 노드로 만들어 다룰 수 있다면 어떻게든 할 수 있을거 같다는 생각이 듭니다.^^

// 해당하는 Id를 가진 요소에 접근하기
const title = document.getElementById('title')

// 해당하는 모든 요소에 접근하기
document.getElementsByTagName('div');

// 해당하는 클래스를 가진 모든 요소에 접근하기
document.getElementsByClassName("divClass")

// css 선택자로 단일 요소에 접근하기
document.querySelector("selector");

// css 선택자로 여러 요소에 접근하기
document.querySelectorAll("selector");

getElementsBy~ 메소드와 querySelectorAll 메소드는 모두 조건에 일치하는 모든 요소를 찾습니다.
하지만 결과물을 콘솔창에서 보면 조금 다릅니다.

const cont = document.getElementById('container');
const item1 = cont.getElementsByTagName('li');
const item3 = cont.querySelectorAll('li');
---------------------------------------------------
item1
HTMLCollection(3) [li, li.item-second, li]

item3
NodeList(3) [li, li.item-second, li]

모두 배열과 비슷한 객체 형태를 가집니다.
차이점은 HTMLCollectionHTML 만 포함하지만, NodeList 는 모든 유형의 DOM 요소 즉, text, 주석 등을 모두 포함합니다.
다른 차이점은 HTMLCollection 은 실시간으로 업데이트 되며, 해당 객체의 각 속성에 대한 변경 사항이 바로 반영됩니다.
반면에 NodeList 는 정적이므로 해당 객체에 대한 변경 사항은 즉시 반영되지 않습니다.

DOM 을 제어 하는 명령어는 여러가지가 있습니다.
첫번째 이벤트 삽입

// HTML
<button>HELLO!</button>

// JavaScript
// 이벤트의 타입에는 click, mouseover, mouseout, wheel 등 다양한 이벤트를 감지합니다.
// listener 함수의 인수에는 이벤트에 대한 정보가 담겨있습니다.

const myBtn = document.querySelector("button");

myBtn.addEventListener('click', function(){
    console.log("hello world");
})

버튼을 클릭하면 콘솔에 hello world 가 출력됩니다.

두번째 클래스 제어

// HTML
<button>Make me BLUE!</button>

// JavaScript
const myBtn = document.querySelector("button");

myBtn.addEventListener('click', function(){

// blue 라는 클래스의 속성 값을 지정 할 수 있습니다.
    myBtn.classList.add("blue");

    // myBtn.classList.remove("blue");     클래스를 제거합니다.
    // myBtn.classList.toggle("blue");     클래스를 토글합니다. 없으면 넣어주고, 있으면 제거합니다.
    // myBtn.classList.contains("blue");   해당하는 클래스가 있는지 확인합니다.
})

객체를 통해 요소의 class 속성을 제어할 수 있습니다.

세번째 요소 제어
DOM API 를 이용해서 요소를 제어할 수 있습니다.

// HTML
<ul></ul>
<button>Make me MORE!</button>

// JavaScript
const myBtn = document.querySelector("button");
const myUl = document.querySelector("ul");

myBtn.addEventListener('click', function(){
    for(let i=0; i < 5; i++){
        const myLi = document.createElement('li');
        myUl.appendChild(myLi);
    }
})

반복문을 통해 버튼을 눌렀을때 5개의 마커가 한번에 생기는 코드입니다.

1. document.createElement(target) : target 요소를 생성합니다.
2. document.createTextNode(target) : target 텍스트를 생성합니다.
3. element.appendChild(target) : target 요소를 element의 자식으로 위치합니다.
4. element.removeChild(target) : element의 target 자식 요소를 제거합니다.
5. element.append(target) : target 요소를 element의 자식으로 위치합니다. 
   appendChild 와 다른점은 노드 뿐만 아니라 여러개의 노드를 한번에, 
   그리고 텍스트도 자식 노드로 포함시킬 수 있다는것 입니다.
6. target.remove() : target 요소를 제거합니다.   

네번째 JavaScript 문자열을 사용해 element, text 노드를 생성하거나 추가하기
DOM API 를 이용하면 요소 안의 값에도 접근하여 값을 가져오거나, 변경할 수 있습니다.

// HTML
<p></p>
<input type="text">
<button>Write Something!</button>

// JavaScript
const myBtn = document.querySelector("button");
const myP = document.querySelector("p");
const myInput = document.querySelector("input");

# 1번
myBtn.addEventListener('click', function(){
    myP.textContent = myInput.value;
});

# 2번
// input 요소에 'input' 이벤트를 연결하면 실시간으로 값이 반영되게 만들 수도 있습니다.
myInput.addEventListener('input', ()=>{
  myP.textContent = myInput.value;
});

myP.innerHTML = "<strong>I'm Strong!!</strong>";

1번은 input 창에 글자를 써 넣고, 버튼을 누르면 글자를 P 태그에 삽입하는 코드이고,
2번은 input 창에 글자를 쓰면 바로 실시간으로 P 태그에 반영되는 코드입니다.
마지막에 있는 innerHTML요소(element) 내에 포함된 HTML 마크업을 가져오거나 설정합니다.
중요한 기능은 innerHTML 로 값을 할당할 때, 마크업으로 변환할 수 있는 문자열이 있다면 마크업으로
만들어 보여준다는 것 입니다. 만약 그런 문자열이 없다면 그냥 문자열만 컨텐츠로 설정합니다.
단, 자바스크립트를 작동시킬 수 있는 가능성이 있으니 나쁜 의도를 가진 사용자가 코드를 입력 할 수 없도록
사용자의 입력 값을 innerHTML 을 통해 할당 받는 일만 없도록 하면 안전하게 사용할 수 있습니다.

다섯번째 속성 제어하기
JavaScript 를 사용해서 요소의 속성을 제어하는 방법은 다양합니다.

1. 요소의 스타일을 제어하는 style 객체
const target = document.querySelector("p");
const txtColor = target.style.color; // 현재 스타일 정보를 가져옵니다.
target.style.color = "red"; // 현재 스타일 정보를 변경합니다.
target.style.fontWeight = "bold"; // 현재 스타일 정보에 font-weight 속성이 없다면 추가합니다.
target.style.color = null; // 현재 스타일 정보를 제거(초기화)합니다.
2. 속성에 접근하고 수정할 수 있는 Attribute 메소드
// HTML
// getAttribute 메소드는 요소의 특정 속성 값에 접근할 수 있도록 합니다.
// setAttribute 메소드는 요소의 특정 속성 값에 접근하여 값을 수정합니다.
<p id='myTxt'>hello lions</p>
<img src='https://static.ebs.co.kr/images/public/lectures/2014/06/19/10/bhpImg/44deb98d-1c50-4073-9bd7-2c2c28d65f9e.jpg'>

// Script
<script>
    const target = document.querySelector('p');
    const myimg = document.querySelector('img');
    const idAttr = target.getAttribute('id');
    console.log(idAttr);
    myimg.setAttribute("src", "https://img.wendybook.com/image_detail/img159/159599_01.jpg");

</script>
3. 요소에 데이터를 저장하도록 도와주는 data 속성
// HTML
<img
    class="terran battle-cruiser"
    src="battle-cruiser.png"
    data-ship-id="324"
    data-weapons="laser"
    data-health="400"
    data-mana="250"
    data-skill="yamato-cannon"
/>

// JavaScript
<script>
    const img = document.querySelector('img')
    console.log(img.dataset);
    console.log(img.dataset.shipId);
</script>

여섯번째 더 인접한곳(Adjacent) 으로 정밀하게 배치하기
insertAdjacentHTML : 요소 노드를 대상의 인접한 주변에 배치합니다.

일곱번째 DOM 안에서 노드 탐색하기

// HTML
<!-- 주석입니다 주석. -->
<article class="cont">
    <h1>안녕하세요 저는 이런 사람입니다.</h1>
    <p>지금부터 자기소개 올리겠습니다</p>
    Lorem ipsum dolor sit amet consectetur adipisicing elit.
    <strong>감사합니다!</strong>
</article>


// JavaScript
const cont = document.querySelector(".cont");
console.log(cont.firstElementChild);  // 첫번째 자식을 찾습니다.
console.log(cont.lastElementChild);   // 마지막 자식을 찾습니다.
console.log(cont.nextElementSibling); // 다음 형제요소를 찾습니다.
console.log(cont.previousSibling);    // 이전 형제노드를 찾습니다.
console.log(cont.children);           // 모든 자식요소를 찾습니다.
console.log(cont.childNodes);         // 모든 자식노드를 찾습니다.
console.log(cont.parentElement);      // 부모 요소를 찾습니다.
// 자기 자신부터 시작해 부모로 타고 올라가며 가장 가까운 cont 클래스 요소를 찾습니다. 단, 형제요소는 찾지 않습니다.
console.log(cont.querySelector('strong').closest('.cont').innerHTML);  

cont.childNodes.cont클래스 안의 요소들을 배열로 모두 저장합니다.
childNodes[1].value 처럼 속성에 접근해서 사용할 수도 있습니다.


여기까지 오늘 배운것들 정리해봤습니다.
기존 과제에 JavaScript 추가하는 과제가 있었습니다.
해보니까 감은 조금 잡히는 거 같습니다. 배열에 요소가 다 들어가 있다면 어쨌든 다룰 수 있는 거니까요.^^
오늘도 충분히 좋은 하루를 보냈으니 내일도 그랬으면 좋겠습니다.
화이팅! 입니다.