[jQuery to Vanilla JS] 1. querySelector를 이용하여 jQuery selector 대체하기

2020. 5. 11. 11:22Front-end/Vanilla JS

반응형
  1. 이론
  2. Element 조회 - 기본 (id, class, tagname 이용)
    2-1) id로 조회 : getElementById
    2-2) class로 조회 : getElementsByClassName
    2-3) tag 이름으로 조회 : getElementsByTagName
  3. Element 조회 - 심화
    1. attribute로 조회
    2. iframe 내부 contents 조회
    3. 부모, 자식, 형제 Element 조회
  4. 속성 조회
    1. input, textarea 요소 value 조회
    2. select 선택된 option의 value, text 조회
    3. 기타 속성 조회 및 설정
    4. data 속성 조회
    5. text contains 조회
    6. index 조회
  5. jQuery 함수 migration
    1. closest
    2. parentsUntil

1. 이론

웹개발자에 매우 익숙한 jQuery.
jQuery는 DOM 처리 및 이벤트를 위한 코드 개발을 매우 간편하게 작성할 수 있는 javascript 라이브러리 입니다.

jQuery는 순수 Javscript(Vanilla JS) 대비 최대 10배 정도의 속도차이가 발생될 수 있으며,
뷰 페이지 로드시 직접 DOM을 만드는 React, Vue, Anglar와 같은 최신 js 기술과 상충되는 면이 있습니다.

IE 10 버전 이상의 최신 브라우저들은 BOM/DOM 처리에 관한 다양한 api들을 제공하고 있어, 특별히 구버전의 브라우저에 서비스를 제공하지 않아도 된다면 아래의 지시를 따라 Vanilla JS로 변환해보는 것을 추천드립니다.

jQuery의 selector를 Vanilla JS의 selector로 바꿔서 DOM 접근해 봅시다.


$(셀렉터)document.querySelector(셀렉터) 또는 document.querySelectorAll(셀렉터)

selector를 이용하여 Element를 찾는 방식에는 querySelector, querySelectorAll 이 있습니다.

document.querySelector는 html 문서 전체를 기준으로 selector를 찾을 경우를 의미합니다.

document.getElementById('demo-form2').querySelectorAll('select');

특정 Element를 기준으로 찾고자할 경우에는 위와 같이 Element에 querySelector를 설정합니다.

06
querySelector는 맨 처음 매칭된 element를 반환하고
querySelectorAll은 매칭된 모든 element들을 NodeList로 반환합니다.

05

조회할 값이 없을 경우
querySelector는 null을 반환하고
querySelectorAll는 []를 반환합니다.

단순한 id, class, tagname을 조회할 때에는 querySelector, querySelectorAll 를 이용하는 것 보다 속도면에서 더 유리한 getElementById, getElementsByClassName, getElementsByTagName 를 사용하는 것을 권장합니다.

$(#아이디)document.getElementById(아이디)
$(.클래스)document.getElementsByClassName(클래스)
$(태그명)document.getElementsByTagName(태그명)


※ 이 포스팅은 You-Dont-Need-jQuery를 참고하여 만들었습니다.


2. Element 조회 - 기본

document 객체 또는 특정 Element를 기준으로 id, class, tag명을 이용하여 간단하게 조회합니다.
querySelector 나 querySelectorAll을 이용하여 조회할 수 있으나, 성능을 위해(속도) getElementById, getElementsByClassName, getElementsByTagName를 사용하는 것을 권장합니다.

2-1) id로 조회 : getElementById

요소.getElementById('아이디')

$('#btn_modify');   // jQuery

document.getElementById('btn_modify'); // Vanilla JS

01

jQuery는 jQuery 프로토타입 객체를 반환하고,
Vanilla JS는 HTMLElement를 반환합니다.


2-2) class로 조회 : getElementsByClassName

요소.getElementsByClassName('클래스명')

$('.nav-item'); // jQuery

document.getElementsByClassName('nav-item'); // Vanilla JS

04

tagname이나 class를 통해 조회할 때에는 HTMLElement의 배열형식인 HTMLCollection를 반환하고, querySelectorAll로 조회하면 NodeList타입으로 반환합니다.


2-3) tag 이름으로 조회 : getElementsByTagName

요소.getElementsByTagName('태그명')

$('input'); // jQuery

document.getElementsByTagName('input'); // Vanilla JS

3. Element 조회

3-1) attribute로 조회

$('input[type=number]'); // jQuery

document.querySelectorAll('input[type=number]'); // Vanilla JS

3-2) iframe 내부 contents 조회 [MDN web docs 참고]

iframe요소.contentDocument

se2_iframe 이라는 id를 갖고 있는 iframe의 contents를 조회해 봅시다.

10


$('#se2_iframe').contents(); // jQuery

document.getElementById('se2_iframe').contentDocument; // Vanilla JS

iframe 내의 document를 반환합니다.

11


document.getElementById('se2_iframe').contentDocument.body.style.height;    // "382px"

iframe 내의 body 요소에 정의된 style중 height속성값을 반환합니다.

document.getElementById('se2_iframe').contentDocument.body.getElementsByTagName('p');

contentsDocument는 document 객체와 같이 getElementById, getElementsByClassName, getElementsByTagName, querySelector, querySelectorAll 메서드를 이용하여 하위 요소를 조회할 수 있습니다.

위의 코드는 body 요소의 하위 p태그 4개를 반환합니다.


3-3)부모, 자식, 형제 Element 조회

12


부모 Element 조회

요소.parentNode

$('#menu-2').parent();  // jQuery

document.getElementById('menu-2').parentNode;   // Vanilla JS

menu-2를 id로 갖는 Element의 부모노드를 조회하면 상위 Element인 id를 d_menus를 갖는 Element가 조회됩니다.


자식 Elements 조회

요소.children

$('#d_menus').children(); // jQuery

document.getElementById('d_menus').children; // Vanilla JS

id가 menu-0~menu-4인 Element들이 조회됩니다.


형제 Elements 조회 - all

형제 Elements는 같은 부모를 갖는 Elements를 의미합니다.
id menu-0의 형제 Elements는 menu-1 ~ menu-4 입니다.(본인 제외)

$("#menu-2").siblings();    // jQuery

jQuery에서는 자식 노드를 조회하는 함수를 제공해주지만, 기본 javascript에서는 별도의 함수를 제공하지는 않습니다.

menu-2의 부모 Element의 자식 Elements 중, 본인을 제외한 Elements를 조회하는 방식으로 조회하면 됩니다.

[...document.getElementById('menu-2').parentNode.children].filter((child) =>
    child !== document.getElementById('menu-2')
); // Vanilla JS, Edge13+

filter적용을 위해 NodeList를 Array로 만들어야 하는데, 위와 같이 [...]를 써도 되고 Array.from()을 이용해도 됩니다.


Array.prototype.filter.call(document.getElementById('menu-0').parentNode.children, function(child) {
  return child !== document.getElementById('menu-0');
}); // Vanilla JS, IE10+

하지만, IE 브라우저에 에서는 Array.from, [...], =>가 호환되지 않기 때문에 IE 브라우저도 지원하고 싶다면 위와 같이 Array.prototype.filter와 function을 명시적으로 설정한 방법을 사용하여 형제 Elements를 조회하면 됩니다.


형제 Element 조회 - prev

요소.previousElementSibling

$('#menu-1').prev(); // jQuery

document.getElementById('menu-1').previousElementSibling; // Vanilla JS

id가 menu-0 Element가 조회됩니다.


형제 Element 조회 - next

요소.nextElementSibling

$('#menu-1').next(); // jQuery

document.getElementById('menu-1').nextElementSibling; //  Vanilla JS

id가 menu-2 Element가 조회됩니다.


4. 속성 조회

4-1) input, textarea 요소 value 조회

요소.value

$('#name').val(); // jQuery

document.getElementById('name').value; // Vanilla JS

4-2) select 선택된 option의 value, text 조회

선택된 option의 value, text 조회해봅시다.

09

$('#sex').val(); // jQuery

document.getElementById('sex').value; // Vanilla JS

select태그의 선택된 option의 value를 조회할 때,
option에 대한 추가 조회 없이 바로 value를 조회할 수 있습니다.

$('#sex option:checked').text(); // jQuery

document.querySelector('#sex option:checked').text; // Vanilla JS

선택된 option에 대한
기타 속성값이나 text값을 읽고자 할 때에는 Pseudo-classes :check로 선택된 요소를 조회한 후 값을 조회합니다.


4-3) 기타 속성 조회 및 설정

요소.getAttribute(속성)
요소.setAttribute(속성, 값)

$('form[name=searchFrm]').attr('method'); // jQuery

document.querySelector('form[name=searchFrm]').getAttribute('method'); // Vanilla JS
$('form[name=searchFrm]').attr('method', 'post'); // jQuery

document.querySelector('form[name=searchFrm]').setAttribute('method', 'post'); // Vanilla JS

속성 조회는 getAttribute. 속성 설정은 setAttribute입니다.


4-4) data 속성 조회

prefix가 data-인 속성을 jQuery를 이용하여 data- 를 제외한 나머지 부분을 camelCase하여 조회할 수 있었습니다.
data-image-url.data('imageUrl')

$('tbody tr:eq(1)').data('href'); // jQuery

document.querySelectorAll('tbody tr')[1].getAttribute('data-href'); // Vanilla JS

.data()를 Vanilla JS로 migration하려면 일반 속성을 조회하듯 getAttribute로 조회할 수 있습니다.
속성 설정은 일반 속성 설정과 같이 setAttribute를 이용하면 됩니다.

IE 11+ 이상의 브라우저에서는 document.querySelectorAll('tbody tr')[1].dataset['href'];로도 조회할 수 있습니다.


4-5) text contains 조회

<td class="text-center">유저22</td>
태그 내의 내용을 text라고 합니다. 이 내용에 일부내용이 포함되는 Element를 조회해봅시다.

jQuery에서는 :contains Pseudo-classes 를 이용하여 텍스트 포함에 관한 필터 적용을 할 수 있었습니다.

:contains는 표준 Pseudo-classes가 아니기 때문에 Vanilla JS로 표현하기 위해서는 별도의 함수를 생성해줘야 합니다.

function contains(selector, text) {
  var elements = document.querySelectorAll(selector);
  return Array.from(elements).filter(function(element) {
    return RegExp(text).test(element.textContent);
  });
}
$('.search_table tbody tr td:contains("유저")'); // jQuery

contains('.search_table tbody tr td', '유저'); // Vanilla JS

유저가 내용에 포함된 td 찾기


4-6) index 조회

Array.prototype.indexOf.call(노드리스트요소, index를 구하고자하는 요소)

querySelectorAll 로 조회가능한 NodeList 중 몇 번째 index인지 조회하는 방법을 알아봅니다.

08

$('.nav-item.active').index('.nav-item'); // jQuery

Array.from(document.querySelectorAll('.nav-item')).indexOf(document.querySelector('.nav-item.active')); // Vanilla JS

active 클래스가 설정된 .nav-item이 몇 번째 index인지 알아봅니다.

Array.prototype.indexOf.call(document.querySelectorAll('.nav-item'), document.querySelector('.nav-item.active'));

IE 브라우저 호환이 필요하다면 형제 Elements 조회 - all에서 처럼 Array.prototype의 내부함수를 이용하면 됩니다.

정적으로 특정 selector가 몇번째 index인지 알아보려면 위와 같이 indexOf의 인자값에 querySelector나 getElementById 등의 함수로 조회한 Element를 넣으면 됩니다.

만약, 클릭 이벤트 발생시 클릭한 Element의 index를 알고자 한다면

var navs = document.getElementsByClassName('nav-item');
[].forEach.call(Array.from(navs), function(nav) {
    nav.addEventListener('click', function(e) {
        var index = Array.prototype.indexOf.call(navs, e.currentTarget);
        ...
    });
});

콜백함수의 currentTarget를 통해 클릭한 요소를 읽어들여 index를 조회할 수 있습니다.


5. jQuery 함수

5-1) closest

기준요소.closest(찾고자하는 요소)
closest(기준요소, 찾고자하는 요소)

$('#btn_modify').closest('form'); // jQuery

document.getElementById('btn_modify').closest('form'); // Vanilla JS (IE를 제외한 최신 브라우저)

closest 함수는 최신브라우저에서도 제공하지만, IE에서는 제공되지 않기 때문에 IE에서 동작하기 위해 별도의 함수를 추가한 후 이용합니다.

function closest(el, selector) {
  const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

  while (el) {
    if (matchesSelector.call(el, selector)) {
      return el;
    } else {
      el = el.parentElement;
    }
  }
  return null;
}
closest(document.getElementById('btn_modify'), 'form'); // Vanilla JS (IE 10+)

5-2) parentsUtil

parentsUtil(기준요소, 찾고자하는 요소)
parentsUtil(기준요소, 찾고자하는 요소, 필터)

기준 Element로부터 설정된 selector와 매칭되는 Element를 조회 까지의 상위 tag를 jQuery 객체로 형태로 List에 담아 반환하는 jQuery 함수입니다.

function parentsUntil(el, selector, filter) {
  const result = [];
  const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

  // match start from parent
  el = el.parentElement;
  while (el && !matchesSelector.call(el, selector)) {
    if (!filter) {
      result.push(el);
    } else {
      if (matchesSelector.call(el, filter)) {
        result.push(el);
      }
    }
    el = el.parentElement;
  }
  return result;
}

parentsUtil 함수를 Vanilla JS로 이용하기 위해 별도로 함수를 정의합니다.
Vanilla JS에서는 jQuery 객체가 아닌 DOM노드 형태를 List에 담아 반환합니다.

$('#btn_modify').parentsUntil('form'); // jQuery

parentsUntil(document.getElementById('btn_modify'), 'form'); // Vanilla JS

form 태그가 나오기 전까지 탐색되는 모든 Elements를 조회합니다.


$('#btn_modify').parentsUntil('form', '.row'); // jQuery

parentsUntil(document.getElementById('btn_modify'), 'form', '.row'); // Vanilla JS

form 태그가 나오기 전까지 탐색되는 모든 Elements 중 class가 row인 Element는 제외하고 조회합니다.


+++

  • jQuery to javascript
  • How to convert jQuery to javascript
  • How to migrate jQuery to javascript
  • How to use querySelector
728x90
반응형