https://www.w3schools.com/js/js_htmldom.asp
https://velog.io/@johnque/JavaScript-HTML-DOM
https://www.youtube.com/watch?v=XGKdimCHzw8
https://yung-developer.tistory.com/m/79
[JavaScript] 자주 사용하는 DOM API 정리
DOM : 브라우저가 생성하는 문서 객체 모델. HTML의 모든 요소(태그를 이루는 그 녀석들, 여는 태그 안에 들어가는 그 속성들, 태그로 감싸져 있는 그 텍스트들)(객체)를 트리 구조로 만듬.
DOM Tree의 요소
Document : 최상위 요소
Root element : 최상위 부모요소 (<html>
)
Element(요소) : 태그로 만든 그놈들 (<head>
, <article>
등)
Attribute(속성) : 여는 태그 안에 들어간 그놈들. ("href"
)
Text : 태그로 둘러 쌓인 그 콘텐츠. DOM은 텍스트만 인식하여 요소(엘리먼트)로 취급함.
이때 DOM Tree를 구성하는 모든 객체들을 node라 할 수 있으며, <a>, href, "네이버"
태그를 만드는 놈들만 칭할 땐 Element라 한다. <a>
메서드 : 자바 스크립트가 HTML의 요소에 취할 수 있는 뭐시기Action.
프로퍼티 : HTML 요소 속 바꾸거나 설정할 수 있는 값Values들.
getElementById()
: 요소를 선택하는 가장 흔한 방법.
innerHTML
: 요소의 컨텐츠를 의미하는 프로퍼티.
<body>
<p id="demo"></p>
<script>
document.getElementById("demo").innerHTML = "Hello World!";
<script>
</body>
위 예시에서
document
객체의 getElementById()
메서드로 <p>
엘리먼트를 불러옴. <p>
엘리먼트의 innerHTML
이라는 프로퍼티에 접근해서 값으로 "Hello World!"를 주었음.따라서 자바스크립트로 <p id="demo"></p>
라는 요소를 <p id="demo">Hello World!</p>
로 바꾸었음.
window.document.getElementById("demo").innerHTML = "Hello World!";
우리엄마window딸document아 주전자element가져와서.get() 안에다가.property 물value 좀 채워
document.getElementById("id명")
document.getElementsByTagName("태그명")
document.getElementsByClassName("클래스명")
element.innerHTML = 새로운 HTML 내용
태그안의 내용물을 바꿔줍니다.
element.attribute = new value
요소의 attribute를 바꿔줍니다.
element.style.property = new style
요소의 스타일을 바꿔줍니다.
element.setAttribute(attribute, value)
요소의 attribute를 value로 설정해줍니다.
document.createElement(element)
새로운 HTML 요소를 생성합니다.
document.removeChild(element)
기존의 HTML 요소를 삭제합니다.
document.appendChild(element)
HTML 요소를 더해줍니다. create로 만들고, append를 통해 적용합니다.
document.replaceChild(new, old)
HTML 요소를 replace 해줍니다.
document.write(text)
HTML 아웃풋 스트림을 통해 출력합니다.
모든 노드 | 요소 노드 (element) | |
---|---|---|
부모 | parentNode | parentElement |
자식 | childNodes firstChild lastChild | children firstChild lastChild |
형제 | previousSibling nextSibling | previousElementSibling nextElementSibling |
document.querySelector(cssSelector) |
모든 노드를 선택하면 NodeList를 반환한다.
Element를 선택하면 HTMLCollection을 반환한다.
NodeList : querySelectorAll 등의 메서드가 반환하는 NodeList 객체는 노드 객체의 상태 변화를 반영하지 않는 non-live DOM 컬렉션 객체입니다. 하지만 childNodes 프로퍼티가 반환하는 NodeList 객체는 HTMLCollection 객체와 같이 실시간으로 노드 객체의 상태 변경을 반영하는 live 객체로 동작합니다. 유사배열객체로서 .forEach() 메서드와 .item(idx)메서드를 지원한다.
HTMLCollection : getElementsByTagname, getElementsByClassName 메서드가 반환하는 HTMLCollection 객체는 노드 객체의 상태 변화를 실시간으로 반영하는 살아있는 live DOM 컬렉션 객체입니다.
배열로 반환하기
NodeList가 유사배열 객체이긴 하지만, NodeList와 HTMLCollection 모두 배열로 반환하여 사용하는 것이 좋다. Array.from(); 메서드를 사용한다.
let arr = Array.from(document.querySelectorAll('h1'));
* : 모든 요소를 선택
태그명 : 해당 태그명으로 선택
태그명[어트리뷰트]: 해당 어트리뷰트를 갖는 태그.
~=는 공백을 기준으로 단어를 포함 (h1[title~="first"]를 선택하면 'heading first'가 선택됨).
^=의 경우 해당 단어로 시작하는 값을 선택 (a[href^="https://"]).
$=로 특정 값으로 끝나는 요소 선택 (a[href$=".html"]).
*=로 특정 요소를 포함한 값을 선택 (a[href*="naver.com"])
#id : id 1개
.class : 클래스명
셀렉터A 셀렉터B: A의 후손요소 (ul li)
셀렉터A > 셀렉터B : A의 자식요소 (div > p)
셀렉터A + 셀렉터B : A의 인접형제 1개
셀렉터A ~ 셀렉터B : A이후의 모든 형제
selector:pseudo-class 가상 클래스 셀렉터
:link - 방문하지 않은 링크
:visited - 방문한 링크
:hover - 셀렉터에 마우스가 올라와 있을 때
:active - 셀렉터가 클릭된 상태일 때
:focus - 셀렉터에 포커스가 들어왔을 때
:checked
:enabled, :disabled
:first-child, :last-child
:nth-child(n), :nth-last-child(n)
nth-child를 사용할 때에 :nth-child(2n)과 같이 사용하여 홀수, 짝수번째만 선택할 수 있다.(음수는 생략된다. 즉 2n-1은 1, 3, 5 순으로 진행된다.)
:first-of-type, :last-of-type, :nth-of-type(n), :nth-last-of-type(n)
:not(셀렉터) : input:not([type=password])
:valid(셀렉터), :invalid(셀렉터) : input태그에 pattern, required로 정합성 검증을 할 때에 사용
selector::pseudo-element 가상 요소 셀렉터
::first-letter
::first-line - 블록 요소 첫번째 줄
::after - 콘텐츠의 뒤
::before - 콘텐츠의 앞
::selection - 드래그한 콘텐츠
document.querySelector(cssSelector);
document.querySelectorAll("li.red");
querySelectorAll은 NodeList(non-live)를 반환한다.
바닐라 자바스크립트의 DOM과 쿼리 셀렉터
document.getElementById(id)
document.getElementsByClassName(class)
document.getElementsByTagName(tagName)
DOM Query에서 GetElements를 하는 경우 HTMLCollection을 반환한다.
HTMLCollection은 live로 결과값을 반환한다. 때문에 반복문 등을 돌릴 때 유의해야 한다. (반복문을 아래에서부터 돌리는 등의 방법으로 우회한다.)
<ul id="testUl">
<li> 인사 나 할까? </li>
</ul>
텍스트를 수정해보자.
const ul = document.getElementById('testUl');
ul.textContent = 'xxxx'
<ul id="testUl">
xxxx
</ul>
통째로 바뀌어 버렸다. 태그를 같이 넣어주자.
ul.textContent = '<li id='speak'> 영어로 인사 해 </li>'
<ul id="testUl">
<li id='speak'> 영어로 인사 해 </li>
</ul>
// (1) 우선 객체를 하나 만든다. // <li></li>
const newLi = document.createElement('li');
// (2) 객체의 프로퍼티에 밸류를 추가한다. // <li>hello world!<li>
nweLi.innerHTML = "hello world!"
//(3) 해당 객체를 append한다.
const ul = document.getElementById('testUl');
ul.appendChild(newLi);
<ul id="testUl">
<li id='speak'> 영어로 인사 해 </li>
<li> hello world! </li>
</ul>
insertBefore(삽입할 요소, 기준이 될 요소)를 통해 특정 위치에 삽입하거나 특정 위치로 옮길 수 있다.
const speak = document.getElementById('speak');
insertBefore(newLi, speak)
<ul id="testUl">
<li> hello world! </li>
<li id='speak'> 영어로 인사 해 </li>
</ul>
speak 엘리먼트의 위로 자리가 옮겨졌다.
노드를 복사할 때에는 .cloneNode(True);
const cloneNewLi = newLi.cloneNode();
그냥 복사하면 <li></li>
로 엘리먼트만 복사된다.
const newCloneNewLi = newLi.cloneNode(True);
?deep 값에 True를 넣어 <li> hello world! </li>
딥카피가 완료됐다.
제거를 할 때에는 .removeChild(요소명)
ul.removeChild(speak);
<ul id="testUl">
<li> hello world! </li>
</ul>
ul.removeChild(ul.lsatElementChild);
<ul id="testUl">
</ul>
.style에 접근하여 프로퍼티와 값을 줄 수 있다.
이때 스타일의 프로퍼티명이 backgorund-color이 아닌 backgroundColor와 같은 카멜케이스인 점에 유의.
ul.style.backgroundColor = 'red';
ul.style.color = '#fff';
아래와 같이 class어트리뷰트의 값을 변경하는 것도 CSS라이브러리를 쓸 때 용이하다.
box.className = 'bg-red mt-3'
classList에 접근하여 add를 하는 것도 가능하다.
box.classList; //DOMTokenList(2) ['bg-red', 'mt-3', value: 'bg-red mt-3]
box.classList.add('txt-white');
box.classList.remove('mt-3');
box.classList.replace('bg-red', 'bg-blue');
box.classList.toggle('bg-blud'); // toggle은 특정 토큰을 비활성화/활성화 한다. 이벤트에 주로 쓰인다.
html의 이벤트는 on와 함께 이벤트를 적었다.
<button onclick="alert('클릭했습니다.')"> 클릭할건가요? </button>
이를 자바스크립트에서 이벤트 객체에 접근하여 이용할 수 있다.
document.getElementById("btn").onclick = alert("클릭했습니다");
하지만 이벤트리스너를 이용하면 콜백함수와 연결할 수 있다.
ELEMENT.addEventListner("이벤트명", sayHello);
onclick
이 아닌 "click"
임에 주의하자.
document.getElementById("btn").addEventListner("click", () -> {
alert('클릭했습니다')
});
매개변수가 없는 익명함수로 위와 같이 처리했다.
왜 자바스크립트는 콜백 합수를 쓸까? 비동기적 프로그래밍(동시적 실행)을 지원하기 위해.
자바스크립트는 싱글프로세스 기반이다.
기존의 프로세스를 중단하지 않고 비동기 API 처리를 진행하기 위해 Web API(웹 브라우저)에서 이벤트 루프(Listner)를 작동한다.
이벤트 루프로 콜백 함수가 작동되면 어쩌구 저쩌구 해서 Call Stack에서 Pop된다.
document.getElementById("btn").removeEventListner("click", () -> {
alert('클릭했습니다')
});
EventTarget.removeEventListener("이벤트명", 콜백함수)
를 실행할 때에도 이벤트명과 삭제할 함수를 기입해야 한다.
window 관련 ui 이벤트
UI 이벤트 – 사용자가 웹페이지가 아닌 브라우저의 UI와 상호작용할 때 발생
이벤트 설명
load 웹 페이지의 로드가 완료되었을 때
unload 웹 페이지가 언로드 될 때(새로운 페이지를 요청한 경우 )
error 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 없는 경우
resize 브라우저의 창 크기를 조정했을 때
scroll 사용자가 페이지를 위아래로 스크롤 할 때
키보드 이벤트
keydown 사용자가 키를 처음 눌렀을 때
keyup 키를 땔 때
keypress 사용자가 눌렀던 키의 문자가 입력되었을 때
마우스 이벤트
click 사용자가 동일한 요소 위에서 마우스 버튼을 눌렀다 땔 때
dbclick 두 번 눌렀다 땔 때
mousedown 마우스를 누르고 있을 때
mouseup 눌렀던 마우스 버튼을 땔 때
mousemove 마우스를 움직였을 때
mouseover 요소 위로 마우스를 움직였을 때
mouseout 요소 바깥으로 마우스를 움직였을 때
포커스 이벤트
focus 요소가 포커스를 얻었을 때
focusin
blur 요소가 포커스를 잃었을 때
focusout
폼 이벤트
input <input>,<textarea>요소 값이 변경되었을 때
change 선택 상자, 체크박스, 라디오 버튼의 상태가 변경되었을 때
submit 사용자가 버튼키를 이용하여 폼을 제출할 때
reset 리셋 버튼을 클릭할 때
cut 폼 필드의 콘텐츠를 잘라내기 했을 때
copy 폼 필드의 콘텐츠를 복사했을 때
paste 폼 필드의 콘텐츠를 붙여넣을 때
select 텍스트를 선택했을 때
윈도우 이벤트
Window.fullScreen
Window.innerHeight 컨텐츠 영역에 대한 높이
Window.innerWidth
Window.location 문서의 위치
Window.screenX
Window.screenY
키보드 이벤트
KeyboardEvent.key
KeyboardEvent.altKey (옵션키 포함)
KeyboardEvent.ctrlKey
마우스 이벤트
MouseEvent.button (en-US)
MouseEvent.clientX DOM 객체에서의 위치
MouseEvent.clientY
MouseEvent.screenX 전체 스크린에서의 위치
MouseEvent.screenY
자식노드에서 이벤트가 발생하면 부모노드로 이벤트가 버블링 됨.
가령 위 사진에서 <li>Red</li>
를 클릭하면 모든 박스에 'click'이벤트가 발생함.
버블링 x | 버블링 O |
---|---|
focus blur mouseenter mouseleave | focusin focusout mouseover mouseout |
앞서 이벤트 리스너는 콜백 함수를 받는다고 하였다. 이 콜백 함수를 '이벤트 핸들러'라고 부른다. 이벤트 핸들러를 이용해 부모 요소에게 이벤트를 위임해보자.
<div id="box">
<ul id="ul">
<li id="one" class="on"> one </li>
<li id="two"> two </li>
<li id="three"> three </li>
<li id="four"> four </li>
</ul>
</div>
위와 같은 태그가 있다.
이를 아래와 같이 이벤트 핸들러를 만든다.
const ul = document.getElementById("ul")
const nums = ul.children;
function clickHandler(event) {
for ( num of nums) {
num.classList.remove("on");
}
event.target.classList.add("on");
}
이벤트가 발생하면 <li>
요소들에서 'on'이라는 클래스를 제거하고, 이벤트가 발생한 <li>
요소에 'on'을 추가하는 핸들러를 만들었다.
document.getElementById("one").addEventListner("click", clickHandler);
document.getElementById("two").addEventListner("click", clickHandler);
document.getElementById("three").addEventListner("click", clickHandler);
document.getElementById("four").addEventListner("click", clickHandler);
ul의 자식요소들에 이벤트리스너를 추가했다. 이를 아래와 같이 부모 요소에 위임할 수 있다.
document.getElementById("ul").addEventListner("click", clickHandler);
자식 요소에 발생한 이벤트는 부모요소로 버블링되므로 이와 같이 위임이 가능하다.
이벤트가 발생한 요소를 target. 이벤트 핸들러가 적용된 요소를 currentTarget이라 한다.
자식에게 발생된 이벤트가 버블링되어 부모 요소의 이벤트 핸들러가 작동되는 경우가 있다.
<div id="box">
<ul id="ul">
<li id="one" class="on"><a href="#"> </a></li>
<li id="two"><a href="#"> two </a></li>
<li id="three"><a href="#"> three </a></li>
<li id="four"><a href="#"> four </a></li>
</ul>
</div>
li태그의 자식요소 a태그를 생성했다.
a 태그를 눌렀을 때
event.target : a tag
event.currentTarget : ul tag
a tag가 ul tag에 이벤트를 위임한 것처럼 동작한다.
아래와 같이 자식요소의 이벤트를 부모요소로 수정할 수 있다.
function clickHandler(event) {
let target = event.target;
if (event.target.tagName === "A") {
event.target = target.parentElement;
}
for ( num of nums) {
num.classList.remove("on");
}
event.target.classList.add("on");
}
또한 ul tag에 이벤트를 위임하였기에 ul tag를 클릭할 때에도 이벤트가 발생한다. 이벤트가 발생하지 않도록 return으로 이벤트 핸들러를 종료하자.
function clickHandler(event) {
let target = event.target;
if (event.target.tagName === "A") {
event.target = target.parentElement;
} else if(target === event.currentTarget){
return
}
for ( num of nums) {
num.classList.remove("on");
}
event.target.classList.add("on");
}
한편 EVENT.stopPropagation();을 통해 이벤트 버블링을 중단시킬 수 있다.
const form = document.getElementById('form');
form.addEventListener('focusin', (event) => {
event.target.style.background = 'pink';
});
form.addEventListener('focusout', (event) => {
event.target.style.background = '';
});
input 태그를 포커스 했을 때에 input태그의 배경색이 분홍이 되도록 짠 코드이다.
이벤트 버블링이 일어나지 않는 focus, blur를 쓰거나 EVENT.stopPropagation();을 하면 위임한 이벤트가 발생하지 않아 배경색이 안 변한다.
const form = document.getElementById('form');
form.addEventListener('focus', (event) => {
event.target.style.background = 'pink';
});
form.addEventListener('focusout', (event) => {
event.stopPropagation()
event.target.style.background = '';
})
event.stopPropagation()으로 버블링을 무작정 막기보다는
event.target과 event.currentTarget을 적절히 바꾸고 이벤트 핸들링 함수를 수정하면서 버블링의 범위를 조절하며 버블링을 활용하는 것이 바람직한 이벤트 핸들링이라 할 수 있겠다.