티스토리 뷰

순수 바닐라 자바스크립트로만으로 웹페이지를 제작하라는 과제를 주어지는 곳들이 꽤나 많다.

왜 실무에 적합한 react대신에 바닐라자바스크립트로 과제를 하라고하는것일까?

바닐라자바스크립트는 모든곳의 근본이기에 꼭 알아야하며, 더 깊숙하게 이해할 수 있다.

 

웹페이지를 만들어보기에 앞서, 구조화를 하는 도중에

한페이지 안에서 모든코드를 처리하는것은 가독성도 좋지않고 복잡해지기때문에

리액트의 컴포넌트화시키는 방법은 정말 간편한거였구나! 라고 생각하며 검색해보다가 

바닐라자바스크립트에서도 리액트처럼 "웹컴포넌트" 를 사용하여 컴포넌트화 시킬수 있다는 것을 발견했다.

 


웹컴포넌트란?


웹 컴포넌트

웹 페이지 혹은 웹 앱에서 커스텀화 / 재사용화 / 캡슐화된 HTML 태그를 만들 수 있는 웹 플랫폼 APIs의 집합

 

웹 컴포넌트는 총 4가지의 주 특징

 

  1. 커스텀 엘리먼트 => 커스텀 엘리먼트는 DOM 엘리먼트의 새로운 타입을 디자인하고 사용하기 위해 기반을 제공합니다.
  2. Shadow DOM => Shadow DOM은 웹 컴포넌트 안에 있는 마크업과 캡슐화된 스타일을 어떻게 사용하는지를 정의합니다.
  3. ES Modules => ES Modules은 JS 문서의 재사용성을 제공합니다.
  4. HTML 템플릿 => 페이지 로드에서는 사용되지 않지만, 런타임에서 인스턴스화를 할 수 있는 마크업을 제공합니다.

 

위의 특징을 사용하여 컴포넌트를 만든다.

커스텀 엘리먼트를 만들어야하는데, shadow DOM을 사용하여 만들면된다.

방법은 아래와같다.

네브바를 제작하고싶다면, NavBar라는 클래스를 만들어준다.

 

1. class 컴포넌트이름 extends HTMLElement {

}  

2. constructor ()와 super()넣기

3. style속성을 위한 createElement("style") => 파일 분리도 가능하나 파일 분리시에 가져오는 기간에 로딩이 바로바로 되지않는다.

어떻게 사용하는가는 사용자의 마음이나. 스타일컴포넌트식으로 이렇게 사용하는것이 사용자입장에서도 로딩되는것을 보지않고 사용자경험에 훨씬 좋기에 분리하지않았다.

 

4. 나머지는 원하는것을 만들어주기만하면된다. createElement로 div를 만들고 classList를 달아주는등등~ DOM조작을하는방법

class NavBar extends HTMLElement {
  constructor() {
    super();

    const style = document.createElement("style");
    style.textContent = `
      .nav {
        position: fixed;
        top: 0;
        width: 100%;
        height: 64px;
        box-sizing: border-box;
        border-bottom: 1px solid rgba(0, 0, 0, 0.2);
        padding: 0px 20px;
        background-color: white;
        z-index: 999;
      }
      .nav_bar {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        height: 100%;
        width: 100%;
      }
      .nav_logo {
        width: 110px;
        height: 20px;
        margin-left: 10px;
      }
      .nav_list {
        display: flex;
        justify-content: space-evenly;
        align-items: center;
      }
      .nav_btn {
        margin: 0px 20px;
        color: rgba(0, 0, 0, 0.7);
      }
      .nav_title {
        min-width: 20px;
        cursor: pointer;
      }
      ul {
        list-style: none;
      }
    `;

    this.attachShadow({ mode: "open" });
    const navContainer = document.createElement("nav");
    navContainer.classList.add("nav");

    const wrapper = document.createElement("div");
    wrapper.classList.add("nav_bar");
    navContainer.appendChild(wrapper);

    const navLogo = document.createElement("img");
    navLogo.setAttribute(
      "src",
      "https://logo.png"
    );
    navLogo.setAttribute("class", "nav_logo");
    navLogo.classList.add("nav_logo");

    const navList = document.createElement("ul");
    navList.classList.add("nav_list");

    const buttonNames = ["타이틀1", "타이틀2", "타이틀3", "타이틀4", "타이틀5"];
    buttonNames.forEach((n) => {
      const newButton = document.createElement("li");
      newButton.classList.add("nav_btn");

      let anchor = document.createElement("a");
      anchor.setAttribute("class", "nav_link");

      let name = document.createElement("span");
      name.textContent = n;
      name.setAttribute("class", "nav_title");
      newButton.append(anchor, name);

      navList.appendChild(newButton);
    });
    wrapper.append(navLogo, navList);

    this.shadowRoot.append(style, navContainer);
  }
}

customElements.define("nav-bar", NavBar);

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함