컴퓨터 공부/🕸️ Web

Javascript 기본 - 2) Window 객체 및 DOM

letzgorats 2023. 11. 30. 18:19

< Window 객체 >

- window 객체는 브라우저에 의해 자동으로 생성되며 웹 브라우저의 창(window)를 나타낸다. 또한 window는 브라우저의 객체이지 javascript 객체가 아니다.

 

- 이 window 객체를 이용해서 

1. 브라우저의 창에 대한 정보를 알 수 있고, 이 창을 제어하고 할 수도 있다.

window 객체 정보

 

2. 또한 var 키워드로 변수를 선언하거나 함수를 선언하면 이 window 객체의 프로퍼티가 된다.

윈도의 객체의 프로퍼티

(ex)

alert, prompt
confirm -> 확인을 누르면 true 값이 전달되어 Yes 가 출력

 

location 정보(window는 모든 객체의 조상인 전역객체로 생략이 가능)
window history객체 와 navigator 객체

- var 로 선언해서 window 객체의 프로퍼티를 만들어야 한다. let과 const는 블록 스코프이기에 window 객체 내부의 블록에서 선언된 것으로 전역 객체의 프로퍼티로 활용될 수 없다.(아래)

var / let


< Dom 이란? >

- 브라우저에서 UI를 볼 수 있는 것은 HTML의 요소를 하나하나 분석해서 보여준 것이다.

- 돔(문서 객체 모델)은 메모리에 웹 페이지 문서 구조를 트리구조로 표현해서 웹 브라우저가 HTML 페이지를 인식하게 해준다.

- 위에서 보는 웹 페이지를 이루는 요소들을 자바스크립트가 이용할 수 있게끔 브라우저가 트리구조를 만든 객체 모델을 의미한다.

html -> dom -> 웹 문서

- 실제 순서는 브라우저가 HTML을 분석해서 DOM 트리를 만든 다음에, 이를 토대로 페이지에 띄워주는 로직이다.

[ 돔 조작 ]

- 위에 보이는 DOM 트리를 DOM에서 제공하는 API를 이용해서 조작할 수 있다.

- API를 이용해서 DOM 구조에 접근하거나 원하는 요소(Element)를 수정하거나 삭제할 수 있다. 이러한 동작을 자바스크립트 코드에서 작성함으로써 수행한다.

 

예를 들어, HTML 코드가 아래와 같다고 하면,

<button class = "button"> Allu Coding </button>

 

JS 코드는 아래와 같이 작성할 수 있다.

// DOM 안에 클래스가 button 이라는 이름을 가진 요소에 접근
var button = document.querySelector('.button');

// DOM 안에 있는 요소의 스타일을 직접 변경(DOM 조작) 
button.onclick = function(){
    this.style.backgroundColor = "red";
};

- 자바스크립트 코드 안에 있지만 실제 document.querySelector 부분은 자바스크립트 자체 요소는 아니다. document 브라우저에서 제공하는 window 객체의 한 부분이다.

알루코딩 버튼이 빨간색으로 변함.

 

그렇다면, 이렇게 DOM 을 조작해서 화면을 변경시켜줄 때 브라우저 내부에서는 어떠한 과정을 통해서 바뀐 화면을 변경시켜주는지 알아보자!


< 웹 페이지 빌드 과정(Critical Rendering Path CRP) >

- 브라우저가 서버에서 페이지에 대한 HTML 응답을 받고 화면에 표시하기 전에 여러 단계가 있다.

- 웹 브라우저가 HTML 문서를 읽고, 스타일 입히고 뷰포트에 표시하는 과정이다.

Critical Rendering Path CRP

※ CSS 객체 모델(CSSOM)

- CSS Object Model은 JavaScript에서 CSS를 조작할 수 있는 API 집합이다. HTML 대신 CSS가 대상인 DOM이라고 생각할 수 있으며, 사용자가 CSS 스타일을 동적으로 읽고 수정할 수 있는 방법이다.

 

- 위의 웹 페이지 빌드 과정에서, DOM과 CSSDOM을 렌더링하는 부분은 비용이 많이 들지 않더라도, Render Tree나 Layout이 짜여지고 그려지는 부분은 비용이 많이 들기에 이 부분을 최소화 하는 것이 성능의 척도이다.

(React 에서는 Virtual Dom을 만들어 가지고 이런 부분을 최소화해준다.)


< Document Object 이용해보기 >

- window 객체가 브라우저 창이라고 하면, document 객체는 브라우저 내에서 콘텐츠를 보여주는 웹 페이지 자체라고 할 수 있다.

document

[ Document 객체 프러퍼티 사용]

- document 객체를 이용해서 웹페이지의 상태와  모든 HTML 태그들에 접근할 수 있다.

doocument 프로퍼티 사용

 

doocument 프로퍼티 사용

[ Document 객체 메소드 사용]

- document 객체의 메소드들을 사용하면 다양한 방법으로 웹페이지 내의 태그들에 접근할 수 있다.

- 밑에서부터는 해당 html 을 가지고 예제를 적용할 것이다.

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Document Object</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <div id="header-container" class="container-fluid p-5 bg-primary text-white text-center">
        <h1 id="header-heading" class="header-title">My First Bootstrap Page</h1>
        <h5>Resize this responsive page to see the effect!</h5>
    </div>

    <div id="body-container" class="container mt-5">
        <div class="row">
            <div class="col-sm-4">
                <h3>Column 1</h3>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
                <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
            </div>
            <div class="col-sm-4">
                <h3>Column 2</h3>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
                <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
            </div>
            <div class="col-sm-4">
                <h3>Column 3</h3>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
                <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
            </div>
        </div>

        <form class="form-container" action="/action_page.php">
            <div id="form-first-div" class="mb-3 mt-3">
                <label for="email" class="form-label">Email:</label>
                <input type="email" class="form-control" id="email" placeholder="Enter email" name="email">
            </div>
            <div class="mb-3">
                <label for="pwd" class="form-label">Password:</label>
                <input type="password" class="form-control" id="pwd" placeholder="Enter password" name="pswd">
            </div>
            <div class="form-check mb-3">
                <label class="form-check-label">
                    <input class="form-check-input" type="checkbox" name="remember"> Remember me
                </label>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>

        <ul class="list-group mt-5 mb-5">
            <li class="list-group-item">An item</li>
            <li class="list-group-item">A second item</li>
            <li class="list-group-item">A third item</li>
            <li class="list-group-item">A fourth item</li>
            <li class="list-group-item">And a fifth one</li>
        </ul>

        <div id='container'>
          innerHTML  innerText       textContent          차이점
            <span style='display:none'>안보이는 텍스트</span>
        </div>

    </div>
    <script src="script1.js"></script>
    <script src="script2.js"></script>
</body>

</html>

 

  • 하나의 요소에 접근
// 파라미터로 전달한 ID를 가진 태그를 반환
document.getElementById(요소아이디);

// 파라미터로 전달한 name 속성을 가진 태그를 반환 
document.getElementByName(name속성값);

// 파라미터로 전달한 선택자에 맞는 첫 번째 태그를 반환
document.querySelector(선택자);
// document.getElementById()
console.log(document.getElementById('header-container'));
console.log(document.getElementById('header-heading').className);
const headerContainer = document.getElementById('header-container');

// styling 변경
headerContainer.style.fontsize = '10px';
headerContainer.style.display = 'none';

// content 변경
headerContainer.textContent = 'Text Content';
headerContainer.innerText = 'Inner Text';
headerContainer.innerHTML = '<span style="color:blue">Inner HTML</span>';

// document.querySelector()
console.log(document.querySelector('#form-first-div'));
console.log(document.querySelector('.form-container'));
console.log(document.querySelector('h5'));

document.querySelector('li').style.color = 'green';
document.querySelector('ul li').style.color = 'pink';

document.querySelector('li:last-child').style.color = 'red';
document.querySelector('li:nth-child(2)').style.color = 'blue';
document.querySelector('li:nth-child(4)').textContent = 'ALLU CODING';
document.querySelector('li:nth-child(odd)').style.backgorund = 'gray';
document.querySelector('li:nth-child(even)').style.backgorund = 'lighgray';
  • 여러 요소에 접근
// 파라미터로 전달한 태그이름을 가진 모든 태그들을 반환(배열)
document.getElementsByTagName(태그이름)

// 파라미터로 전달한 클래스 이름을 가진 모든 태그들을 반환(배열)
document.getElementsByClassName(클래스이름)

// 파라미터로 전달한 선택자에 맞는 모든 태그들을 반환(배열)
document.querySeletorAll(선택자)
// document.getElementsByClassName
const items = document.getElementsByClassName('list-group-item');
console.log(items);
console.log(items[0]);
items[0].style.color = 'green';
items[3].textContent = 'Allu';

// document.getElementsByTagName
let list = document.getElementsByTagName('li');
console.log(list);
console.log(list[0]);
list[0].style.color = 'pink';
list[3].textContent = 'Coding';

// HTML 모음을 배열로 만들기
list = Array.from(list);

list.reverse();

list.forEach(function(li,index){
	console.log(li.className);
    li.textContent = `${index}. List`;
});

console.log(list);

// document.querySelectorAll
const items = document.querySelectorAll('ul.list-group li.list-group-item');

items.forEach(function(item,index){
    item.textContent = `${index}. List`;
});

const liOdd = document.querySelectorAll('li:nth-child(odd)');
const liEven = document.querySelectorAll('li:nth-child(even)');

liOdd.forEach(function (li,index){
	li.style.background = 'lightgray';
});

for (let i=0;i< liEven.length; i++){
	liEven[i].style.background = 'gray';
}

console.log(items);

 

[ innerHTML vs innerText vs textContent ]

  • innerHTML html 까지 같이 보여준다.
  • innerText사용자에게 보여지는 텍스트 값을 읽어오며 여러 공백은 무시하고 하나의 공백만 처리한다. ( html에서 작성할 때, 스페이스 공백이 많아도 사용자에게는 공백 하나로 보여지는 것처럼 사용자에게 보여지는 그대로 보여진다.)
  • textContent는 display:none 스타일이 적용된 숨겨진 텍스트도 가져오는 노드가 가지고 있는 텍스트 값 그대로 보여준다. ( html에서 작성한 그대로가 보여진다고 보면 된다.)

< Dom 탐색하기 >

- DOM을 이용하면 요소와 요소의 콘텐츠에 무엇이든 할 수 있다. 하지만, 무언가를 하기 전에, 우리가 조작하고자 하는 DOM 객체에 접근하는 것이 선행되어야 한다.

- DOM에 수행하는 모든 연산은 document 객체에서 시작한다. document 객체는 DOM에 접근하기 위한 '진입점' 일 뿐이다.

- 진입점을 통과하면 그 어떤 노드에도 접근할 수 있는 셈이다.

document는 DOM 에 접근하기 위한 진입점!

[ 자식 노드 탐색하기 ]

- childNodes, firstChild, lastChild 로 자식노드를 탐색할 수 있다.

- 밑에서부터는 해당 html 을 가지고 예제를 적용할 것이다.

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Dom Traverse</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <div id="body-container" class="container mt-5">
        <ul class="list-group mt-5 mb-5">
            <li class="list-group-item 1">An item</li>
            <li class="list-group-item 2">A second item</li>
            <li class="list-group-item 3">A third item</li>
            <li class="list-group-item 4">A fourth item</li>
            <li class="list-group-item 5">And a fifth one</li>
        </ul>
    </div>
    <script src="script.js"></script>
</body>

</html>
let val;
const list = document.querySelector('ul.list-group');
const listItem = document.querySelector('li.list-group-item:first-child');

val = listItem;
val = list;

// child nodes 반환

val = list.childNodes;
val = list.childNodes[0];
val = list.childNodes[0].nodeName;
val = list.childNodes[3];
val = list.childNodes[3].nodeType;

// //nodeType
// 1 - Element
// 2 - Attribute
// 3 - Text node
// 8 - Comment <!-- Comment Node -->
// 9 - Document itself
// 10 - Doctype

// children element nodes 반환
val = list.children; // HTML Collection을 반환(line break 포함 x)
val = list.children[1];
list.children[1].textContent = 'Hi';

// First child
val = list.firstChild;
val = list.firstElementChild; // text node를 포함 x

// Last child
val = list.lastChild;
val = list.lastElementChild;

// child 요소 count
val = list.childElementCount;

// parent node 반환
val = listItem.parentNode;
val = listItem.parentElement;
val = listItem.parentElement.parentElement;

// next sibling 반환
val = listItem.nextSibling;
val = listItem.nextElementSibling;
val = listItem.nextElementSibling.nextElementSibling;
val = listItem.nextElementSibling.nextElementSibling.previousElementSibling;

// previous sibling 반환
val = listItem.previousSibling;
val = listItem.previousElementSibling;
console.log(val);

 

  • 자식 노드 : 바로 아래의 자식 요소를 나타낸다.
  • 후손 노드 : 중첩 관계에 있는 모든 요소를 의미한다. 자식 노드와 그 보다 자식 노드 모두가 후손 노드가 된다.

[ DOM 컬렉션 ]

- childNodes는 마치 배열 같아 보인다.

- 하지만, childNodes는 배열이 아닌 반복 가능한(iterable) 유사 배열 객체인 컬렉션(Collection) 이다.

childNodes

- childNodes 가 컬렉션이기에 가지는 특징

  1. 비록 배열은 아니지만, forEach(), for ... of 를 사용할 수 있다. ( for ... in 은 사용 불가하다.)

for ... of => 배열을 순환할 때 사용 / for .. in 은 객체를 순환할 때 사용

 

    2. 배열이 아니기에 배열 메서드 사용 불가능하다.

filter 메서드 사용 불가 -> undefined 가 나온다.

    3. 위의 경우에 배열 메서드를 사용하고 싶다면, Array.from 을 사용하면 진짜 배열을 만들 수 있다.

Array.from을 통해 배열로 변환 가능
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from


< CreateElement >

- 요소를 생성할 때, html 에서 바로 태그를 생성해도 되지만, 자바스크립트로 생성할 수 있다.

- document.createElement(tagName); 처럼 createElement 메서드에 태그 이름을 넣어서 요소를 생성할 수 있다.

- 밑에서부터는 해당 html 을 가지고 예제를 적용할 것이다.

<!DOCTYPE html>
<html lang="en">

<head>
    <title>CreateElement</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <div id="body-container" class="container mt-5">
        <ul class="list-group mt-5 mb-5">
            <li class="list-group-item">An item</li>
            <li class="list-group-item">A second item</li>
        </ul>
    </div>
    <script src="script.js"></script>
</body>

</html>
// element 생성
const li = document.createElement('li');

// class 추가하기
li.className = 'list-group-item';

// id 추가하기
li.id = 'new-item';

// attribute 추가하기
li.setAttribute('name','New list itme');

// 새로운 text node 생성하고 더하기
li.appendChild(document.createTextNode('New list item '));

// 새로운 link element 생성하기
const link = document.createElement('a');

// classes 추가하기
link.className = 'alarm-item';

// icon html 추가하기
link.innerHTML = '<id class="bi-alarm"></i>';

// link를 li에 더하기
li.appendChild(link);

// li 를 ul의 자식으로 더하기
document.querySelector('ul.list-group').appendChild(li);

console.log(li);

createElement


< removeChild & replaceChild >

- 자바스크립트로 요소를 생성하는 것도 있겠지만, 삭제하고 교체하는 것도 있다.

- 밑에서부터는 해당 html 을 가지고 예제를 적용할 것이다.

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Remove, Replace</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <div id="body-container" class="container mt-5">
        <ul class="list-group mt-5 mb-5">
            <li class="list-group-item">An item</li>
            <li class="list-group-item">A second item</li>
        </ul>
        <div id="A">Hello</div>
    </div>
    <script src="script.js"></script>
</body>

</html>

[ removeChild ]

  • parentNode.removeChild(node);
  • 하나의 노드를 삭제한다.
  • 삭제할 때는 삭제 할 노드를 자식으로 가진 부모 노드에서 실행된다.
const listParent = document.querySelector('ul');
const list = document.querySelectorAll('li');

listParent.removeChild(list[1]);

삭제 전 , 삭제 후
removeChild

[ replaceChild ]

  • parentNode.replaceChild(new Child, old Child);
  • 원래 있는 Child를 삭제하고 새 Child로 교체한다.
  • 교체할 때는 교체할 노드를 자식으로 가진 부모 노드에서 실행된다.
const oldElement = document.getElementById('A');
const newElement = document.createElement('span');
newElement.textContent = "Allu";
oldElement.parentNode.replaceChild(newElement, oldElement);

교체 전, 교체 후
replaceChild


참고 자료

따라하며 배우는 자바스크립트 A-Z

반응형