Javascript study

[JS] getElement~, querySelector~로 요소 검색하기

카누가 좋아요 2023. 8. 18. 21:39

📌 참고 사이트

getElement*, querySelector*로 요소 검색하기 (javascript.info)

 

getElement*, querySelector*로 요소 검색하기

 

ko.javascript.info

 

 

 

📋 document.getElementById 혹은 id를 사용해 요소 검색하기

HTML 요소에 id 속성이 존재한다면 위치에 상관없이 메서드 document.getElementById(id)를 이용해 접근이 가능하다.

 

ex)

💻 HTML

 

...
<div id="element">
  <div id = "element-content"></div>
</div>
...

 

💻 JS

 

// 요소 가져오기
const element = document.getElementById('element');

// 요소의 배경색 변경하기
element.style.backgroundColor = 'red';

 

❗ 주의할 점

➡️ anyNode.getElementById가 아닌, document.getElementById의 형식으로 작성해야 한다.

즉, 앞에 아무 노드나 적어주면 안되고, 오직 document만 가능하다. 

➡️ HTML에서 id 속성값을 중복되게 설정하면 getElementById를 사용했을 때 어떤 요소를 반환할지 판단하지 못해 임의의 요소가 반환되므로 HTML 문서 내에서 동일 id가 존재하지 않게 하자.

 

 

 

📋 querySelectorAll

element.querySelectorAll(선택자) 의 형식으로 사용하며, 이 메서드는 주어진 CSS 선택자에 대응하는 요소 '모두'를 반환한다.

 

ex)

💻 HTML

 

<ul>
  <li>1-1</li>
  <li>1-2</li>
</ul>
<ul>
  <li>2-1</li>
  <li>2-2</li>
</ul>

 

💻 JS

 

// ul > li:first-child에 해당하는 모든 HTML 요소들이 반환된다.
const elements = document.querySelectorAll('ul > li:first-child');

for (let element of elements) {
  console.log(element);
}

// <li>1-1</li>
// <li>1-2</li>

 

💡 querySelectorAll을 사용하면 :hover나 :active 같은 가상 클래스를 사용해서도 선택을 할 수 있다.

예를 들어 document.querySelectorAll(':hover')를 사용하면 마우스 포인터가 hover 상태인 요소 모두를 담은 컬렉션이 반환된다.

 

 

 

📋 querySelector

element.querySelector(선택자) 의 형식으로 사용하고, 주어진 CSS 선택자에 대응하는 요소 중 첫 번째 요소를 반환한다.

element.querySelectorAll(선택자)[0]과 같은 동작을 한다.

querySelector는 해당하는 요소를 찾으면 검색을 멈추기 때문에 querySelectorAll보다 더 빠르면서 코드 길이도 더 짧아진다는 장점이 있다.

 

 

 

📋 matches

element.matches(선택자)요소(element)가 주어진 CSS 선택자와 일치하는지 여부를 판단해 준다.

일치한다면 true, 아니라면 false를 반환한다. (DOM을 검색하는 일을 하는 것이 아니다.)

요소가 담겨있는 배열 등을 순회할 때 원하는 요소만 걸러내고자 할 때 유용하다.

 

ex)

💻 HTML

 

....
<a href="http://example.com/file.zip">...</a>
<a href="http://ya.ru">...</a>
....

 

💻 CSS

 

// 컬렉션이라면 matches 메서드 적용이 가능하다.
for (let element of document.body.children) {
  // href 속성 값이 zip으로 끝나는 요소만 걸러낸다.
  if (element.matches('a[href$="zip"]')) {
    console.log('주어진 CSS 선택자와 일치하는 요소' + element.href);
  }
}

 

 

 

📋 closet

element.closet(선택자) 의 형식으로 closet 메서드를 사용하면 element 자기 자신을 포함하여 CSS 선택자와 일치하는 가장 가까운 조상 요소를 찾을 수 있게 도와준다.

 

ex)

 

💻 HTML

 

.....
<h1>목차</h1>
<div class="contents">
  <ul class="book">
    <li class="chapter">1장</li>
    <li class="chapter">2장</li>
  </ul>
</div>
.....

 

💻 CSS

 

let chapter = document.querySelector('.chapter');     // li를 의미

console.log(chapter.closet('.book'));     // ul을 찾아줌.
console.log(chapter.closet('.contents'));     // div를 찾아줌.

console.log(chapter.closet('h1'));     // null (h1은 li의 조상 요소가 아니기 때문)

 

 

 

📋 getElementsBy~

📍 element.getElementsByTagName(tag)

주어진 태그에 해당하는 요소를 찾고, 대응하는 요소를 담은 컬렉션을 반환한다.

매개변수 부분인 tag에 *가 들어가면 모든 태그가 검색된다.

 

📍 element.getElementsByClassName(className)

class 속성값을 기준으로 요소를 찾고, 대응하는 요소를 담은 컬렉션을 반환한다.

 

📍 document.getElementsByName(name)

검색 기준은 name 속성값으로, 문서 전체를 대상으로 검색을 수행한다.

역시 검색 결과를 담은 컬렉션을 반환한다.

 

❗ Id의 경우는 Element(s를 적지 않음), TagName, ClassName, Name의 경우는 모두 Elements, 즉 s를 작성해야 한다.

 

 

 

📋 HTMLCollection과 NodeList

📍 각 메서드가 반환하는 것

➡️ getElementById  querySelector  요소 하나만을 반환한다.

➡️ getElementsBy~ 형태의 메서드와 children 프로퍼티는 HTMLCollection을 반환한다.

➡️ querySelectorAll  getElementsByNamechildNodes 프로퍼티는 NodeList를 반환한다.

 

📍 HTMLCollection과 NodeList의 공통점

➡️ DOM API가 여러 개의 결과값을 한번에 반환하기 위한 DOM 컬렉션 객체이다.

➡️ 배열이 아니고, 유사 배열 객체반복 가능(iterable)하다. 그러므로 for ... of문으로 순회가 가능하고, 배열의 다양한 메서드(map 같은)를 적용하고 싶다면 Array.from 메서드나 전개 연산자(...)를 사용하여 배열로 만들어 사용해야 한다.

 

📍 HTMLCollection과 NodeList의 차이점

HTMLCollection은 객체가 스스로 실시간 노드 객체의 상태 변경을 반영하는 Live 객체이다.

또한, forEach() 메서드를 가지고 있지 않기 때문에 배열로 만들어 사용해야 한다.

객체의 각 요소에 접근하고 싶다면 배열의 인덱스로 접근하면 된다.

 

💻 HTMLCollection 예시

<HTML>

.....
<ul id="fruits">
  <li class="red">Apple</li>
  <li class="red">Banana</li>
  <li class="red">Orange</li>
</ul>
.....

 

<CSS>

 

.red {
color: red;
}

.blue {
color: blue;
}

 

<JS>

 

const fruits = document.getElementsByClassName(".red");
// getElementsByTagName은 클래스가 red인(글자색이 red인) 요소들의 HTMLCollection을 반환한다.

// 반환된 HTMLCollection을 0번부터 하나씩 순회
for (let i = 0; i < $fruits.length; i++) {
  // 각 요소의 className을 blue로 변경(글자색을 blue로)
  fruits[i].className = "blue";
}

 

fruits는 3개의 <li> 요소가 담겨 있는 HTMLCollection을 반환한다.

0번 요소의 클래스명이 blue로 바뀌게 되면, 이제 0번 <li> 요소는 더 이상 클래스명이 red가 아니게 되므로 바로바로 반영이 되어 HTMLCollection에서 빠지게 된다. 

이 시점에서 HTMLCollection에는 1번 요소였던 <li>와 2번 요소였던 <li>만 남아있게 된다.

다음 인덱스는 1이 되는데, 길이가 2인 컬렉션에서 1번째 요소는 처음에 2번 요소에 해당했던 <li>이므로 그것의 클래스명이 blue로 바뀌고 나서 순회가 끝나게 된다.

1번 <li>의 클래스명은 변함없이 red로 남아 있는 의도치 않은 일이 발생했다. 

따라서 HTMLCollection을 순회할 때에는 위와 같은 경우를 조심해야 한다.

 

 

NodeList노드가 변경되어도 그 상태를 바로 반영하지 않는 Non-live 객체이다.

forEach(), entries(), keys(), values()의 메서드를 사용 가능하다.

단, childNodes 프로퍼티의 경우 live 객체임에 주의해야 한다.

 

💻 NodeList 예시

HTML과 CSS는 위의 예시와 같고, NodeList를 얻기 위해 JS만 수정해 보겠다.

 

<JS>

 

const $fruits = document.querySelectorAll(".red");
// querySelectorAll은 nodeList를 반환한다.

for (let i = 0; i < $fruits.length; i++) {
  $fruits[i].className = "blue";
}

 

HTMLCollection 때와는 다르게 클래스가 blue로 바뀌어도 nodeList에서 해당 요소가 사라지지 않는다.

따라서 nodeList에 있는 모든 요소들을 차례대로 클래스를 변경하는 것이 가능하다.

 

 

https://velog.io/@jangws/HTMLCollection-vs-NodeList-%EB%91%98%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%95%8C%EA%B3%A0-%EC%9E%88%EB%82%98%EC%9A%94

 

HTMLCollection vs NodeList 둘의 차이를 알고 있나요?

HTML의 구조나 내용 또는 스타일 등을 동적으로 조작할 필요가 자주 있는데, 이를 위해서는 먼저 요소 노드를 취득해야 한다.같은 class 어트리뷰트 값을 갖는 모든 요소 노드들을 취득하기 위한

velog.io

 

 

 

📋 contains

elementA.contains(elementB) 형식으로 작성하면 elementB가 elementA에 속하거나(elementB가 elementA의 후손이거나) elementB와 elementA가 같은 노드일 때 을 반환한다.

 

 

 

✏️ 과제

📍 요소 검색하기

테이블과 폼이 있는 문서가 있다고 가정해 보자.

아래 조건에 맞는 요소는 어떤 방식으로 찾을 수 있을까?

1️⃣ id="age-table"인 테이블

2️⃣ 위 테이블 내의 label 요소 모두 

3️⃣ 위 테이블 내의 첫 번째 td

4️⃣ name="search"인 form

5️⃣ 위 폼의 첫 번째 input

6️⃣ 위 폼의 마지막 input

 

🅰️

1️⃣ document.getElementById('age-table')

2️⃣ document.getElementsByTagName('label') 또는 document.querySelectorAll('#age-table label')

3️⃣ document.querySelector('#age-table td:first-child') 또는 document.querySelector('#age-table td')

4️⃣ document.getElementsByName('search')[0] 또는 document.querySelector('form[name="search"]')

5️⃣ 위에서 접근한 폼을 form이라 하면, form.querySelector('input') 또는 form.getElementsByTagName('input')[0]

6️⃣ form.querySelectorAll('input')[form.querySelectorAll('input').length - 1]