Frontend

jQuery를 VanillaJS로 대체하기

Monotask 2019. 9. 7. 16:07

최근 대부분의 브라우저는 ES6를 지원합니다. 
jQuery는 엘리먼트 선택이나 이벤트 등록, 데이터 요청 등의 작업에서 브라우저 호환성에 신경쓰지 않고  사용할 수 있는 편리한 메소드를 제공해 주었습니다. 
그러나 이제는 더 이상 라이브러리에 의존하지 않아도 되도록 브라우저 환경이 발전해 왔습니다.

이 글에서 VanillaJS는 아무 라이브러리도 사용하지 않는 순수 자바스크립트(ES6)를 의미합니다.

다음 작업들에 대해서 jQuery구현과 VanillaJS구현을 알아보겠습니다.

  • 엘리먼트 선택
  • 이벤트
  • 스타일 적용
  • Document 로딩 완료 이벤트
  • class 등록과 삭제
  • ajax 요청
  • 엘리먼트 생성
  • DOM 제어

 

 

엘리먼트 선택

jQuery의 jQuery의 셀렉터인 $()는 querySelector로 대체될 수 있습니다.

// jQuery: 모든 .element 인스턴스 선택
$.(".element");

// .element 첫번째 요소만 선택
document.querySelector(".element");

// .element 모든 요소 선택
document.querySelectorAll(".element");

 

선택된 요소에 함수 실행

querySelectorAll()은 jQuery와 마찬가지로 배열을 리턴합니다. 

jQuery 에서는 선택된 배열을 하나의 객체로 취급하여 함수를 한 번만 호출하면 되지만, VanillaJS에서는 배열을 루프를 돌며 각각 호출해 주어야 합니다.

// jQuery에서 모든 요소 안보이게 하기
$(".element").hide();

// VanillaJS에서는 .element 엘리먼트 배열의 각 원소마다 함수를 호출
document.querySelectorAll(".element").forEach(ele => { ele.style.display = "none" }

 

선택된 엘리먼트 배열에서 특정 요소 찾기

jQuery에서 find()는 querySelector()를 체인으로 호출하여 구현할 수 있습니다.

// jQuery에서 .container 엘리먼트들중 .element의 첫 번째 엘리먼트 가져오기
var container = $(".container");
container.find(".element");

// VanillaJS에서 동일한 기능 수행
var container = document.querySelector(".container");
container.querySelectorAll(".element");

 

엘리먼트 트리 구조 탐색

특정 엘리먼트의 부모, 형제 엘리먼트를 선택하는 방법입니다.

// jQuery
$(".element").next();
$(".element").prev();
$(".element").parent();

// VanillaJS
var element = document.querySelector(".element");
element.nextElementSibling;
element.previousElementSibling;
element.parentElement;

 

이벤트

jQuery에서 이벤트를 등록하는 방법은 여러가지가 있습니다. 
VanillaJS에서는 addEventListener로 모두 대체됩니다.

// jQuery
$(".element").click(function(e) { /* 클릭 이벤트 처리 */ });
$(".element").mouseenter(function(e) { /* 클릭 이벤트 처리 */ });
$(document).keyup(function(e) { /* 키 입력 이벤트 처리 */ });

// vanillaJS
document.querySelector(".element").addEventListener("click", (e) => { /* ... */ });
document.querySelector(".element").addEventListener("mouseenter", (e) => { /* ... */ });
document.addEventListener("keyup", (e) => { /* ... */ });

 

동적으로 추가되는 엘리먼트에 이벤트 등록

jQuery의 on()은 동적으로 추가되는 엘리먼트에 실시간으로 이벤트 등록을 해주는 메소드입니다.
VanillaJS에서는 우선 엘리먼트를 생성하여 DOM에 추가된 후 이벤트 핸들러를 등록해주는 방법을 사용해야 합니다.

// jQuery
// .item 엘리먼트가 DOM에 동적으로 추가 되는 경우에도 클릭 이벤트를 처리할 수 있다
$(".list").on("click", ".item", handleClick);

// VanillaJS
// 엘리먼트를 생성하고 DOM에 추가
var list = document.createElement("div");
document.querySelector(".item").appendChild(list);
// 엘리먼트에 이벤트 등록
list.addEventListener("click", handleClick);

 

커스텀 이벤트 생성과 실행

이벤트를 수동으로 실행시키는 trigger()는 dispatchEvent()로 대체될 수 있습니다.

// jQuery
// document와 .element에서 customEvent 실행
$(document).trigger("customEvent");
$(".element에서").trigger("customEvent");

// vanillaJS
// customEvent 생성과 실행
document.dispatchEvent(new Event("customEvent"));
document.querySelector(".element에서").dispatchEvent(new Event("customEvent"));

 

스타일 적용

스타일을 적용하는 css()메소드는, 각 엘리먼트의 style속성에 값을 대입하는 것으로 같은 기능을 할 수 있습니다.

// jQuery
// .element 를 선택하고 텍스트 색상을 검정으로 변경
$(".element").css("color", "#000");

// vanillaJS
// .element 에 해당하는 첫번째 엘리먼트를 선택하고 텍스트 색상을 검정으로 변경
document.querySelector(".element").style.color = "#000";

 

jQuery에서는 키-값 구조의 객체를 전달하여 여러 속성을 한번에 적용할 수 있습니다.
VanillaJS에서는 각 값을 문자열로 한번에 전달할 수 있지만, 약간의 제약사항이 있습니다.

// jQuery
// 여러개의 스타일 적용
$(".element").css({
    "color": "#000",
    "Background-color": "red"
});

// vanillaJS
// 스타일을 한번에 적용 (그러나 이 엘리먼트에 있던 모든 CSS가 사라지고 이것으로 대체된다)
element.style.cssText = "color: #000; background-color: red";

 

Document 로딩 완료 이벤트

모든 DOM객체가 로딩되었음을 알 수 있는 $(document).ready()를 다음과 같이 구현할 수 있습니다.

// jQuery
$(document).ready(function() {
    /* DOM이 완전히 로드된 후에 할 일들 */
});

// vanillaJS
// 메소드를 정의하고 그것을 호출한다
var ready = (callback) => {
    if (document.readyState != "loading") callback();
    else document.addEventListener("DOMContentLoaded", callback);
}

ready(() => {
    /* DOM이 완전히 로드된 후에 할 일들 */
});

 

class 등록과 삭제

class관련 메소드는 classList속성으로 같은 기능을 할 수 있습니다.

// jQuery
// focus 클래스의 추가, 제거, 적용/비적용
$(".element").addClass("focus");
$(".element").removeClass("focus");
$(".element").toggleClass("focus");

// vanillaJS
// focus 클래스의 추가, 제거, 적용/비적용
var element = document.querySelector(".element");
element.classList.add("focus");
element.classList.remove("focus");
element.classList.toggle("focus");

 

classList는 여러개의 클래스를 동시에 제어할 수 있습니다.

// focus, highlighted 클래스를 추가하고, 다시 제거한다
var element = document.querySelector(".element");
element.classList.add("focus", "highlighted");
element.classList.remove("focus", "highlighted");

 

상호배타적인 두 개의 클래스를 서로 교체하는 replace() 메소드가 있습니다.

// focus클래스를 제거하고 blurred클래스를 추가
document.querySelector(".element").classList.replace("focus", "blurred");

 

엘리먼트에 특정 클래스가 적용되어 있는 확인 하려면,  classList속성의 contains()메소드를 사용합니다.

// jQuery
// "focus" 클래스가 적용 되어있는지에 따라 작업 수행
if ($(".element").hasClass("focus")) {
    // 작업 수행
}

// vanillaJS
// "focus" 클래스가 적용 되어있는지에 따라 작업 수행
if (document.querySelector(".element").classList.contains("focus")) {
    // 작업 수행
}

 

ajax 요청

fetch()는 비동기 네트워크 요청을 생성하는 메소드입니다. URL을 파라미터로 받아 서버 응답을 처리하는 Promise객체를 리턴합니다.

// jQuery
$.ajax({
    url: "data.json"
    }).done(function(data) {
        // 응답 처리
    }).fail(fucntion() {
        // 에러 처리
    });

// vanillaJS
fetch("data.json")
    .then(data => {
        // 응답 처리
    }).catch(error => {
        // 에러 처리
    });

 

엘리먼트 생성

createElement()에 원하는 태그 이름을 전달하여 엘리먼트를 생성합니다.

// jQuery
$("<div/>");
$("<span/>");

// VanillaJS
document.createElement("div");
document.createElement("span");

 

DOM 제어

엘리먼트의 텍스트를 업데이트 하기 위해 흔히 innerHTML을 사용합니다만, 이것은 XSS공격에 취약합니다. textContent속성을 이용하면 안전하게 텍스트를 읽거나 수정할 수 있습니다.
그러나 innerHTML처럼 엘리먼트 추가와 같은 작업을 할 수 없습니다. 이 속성은 전달된 텍스트를 모두 원본(raw) 텍스트로 표현합니다.

var element = document.createElement("div");
element.textContent = "Text";
// 또는 텍스트 노드를 생성하고 그것을 DOM에 추가한다.
var text = document.createTextNode("Text");
element.appendChild(text);

 

새로운 엘리먼트의 생성과 추가는 appendChild()를 사용합니다.

// jQuery: div을 생성하고 .container에 붙인다
$(".container").append($("<div/>"));

// VanillaJS: div을 생성하고 .container에 붙인다
var element = document.createElement("div");
document.querySelector(".container").appendChild(element);