본문 바로가기
JavaScript

[JavaScript]바닐라자바스크립트 컴포넌트생성하기

by hans-j 2023. 12. 5.

 

파일구조

// 페이지(컴포넌트) 임포트
import Home from "./public/pages/Home.js";
import Design from "./public/pages/Design.js";
import Board from "./public/pages/Board.js";
import Submit from "./public/pages/Submit.js";

// 경로 문자열을 정규 표현식으로 변환하는 함수
const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\\/").replace(/:\w+/g, "(.+)") + "$");

// 매개변수와 일치하는 값을 추출하는 함수
const getParams = match => {
    const values = match.result.slice(1);
    const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]);

    return Object.fromEntries(keys.map((key, i) => {
        return [key, values[i]];
    }));
};

// URL을 변경하고 새로운 페이지를 로드하는 함수
const navigateTo = url => {
    history.pushState(null, null, url);
    window.scrollTo(0, 0);
    router(); // 새로운 페이지 로드
}

// 라우터 함수
const router = async () => {
    // 라우트와 페이지(컴포넌트) 매핑
    const routes = [
        { path : "/", pages : Home},
        { path : "/design", pages : Design},
        { path : "/board", pages : Board},
        { path : "/submit", pages : Submit}
    ];

    // 현재 URL 경로에 대응하는 라우트를 찾음
    const potentialMatches = routes.map(route => {
        return {
            route : route,
            result : location.pathname.match(pathToRegex(route.path))
        };
    });

    // 매칭된 라우트 찾기
    let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
    
    // 매칭된 라우트가 없을 경우 기본 라우트로 설정
    if (!match) {
        match = {
            route : routes[0],
            result : [location.pathname]
        };
    }

    // 매칭된 라우트에 대응하는 페이지 인스턴스 생성
    const pages = new match.route.pages(getParams(match));

    // 페이지의 HTML을 가져와서 #app 요소에 삽입
    document.querySelector("#app").innerHTML = await pages.getHTML();
    
    // 페이지의 실행 스크립트 실행
    await pages.executeScript();
};

// 브라우저 히스토리의 상태 변화에 대응하여 라우터 함수 호출
window.addEventListener("popstate", router);

// 문서가 완전히 로딩되면 실행되는 이벤트
document.addEventListener("DOMContentLoaded", ()=> {
    // 클릭 이벤트를 리스닝하여 [data-link] 속성이 있는 링크가 클릭되면 페이지 전환 처리
    document.body.addEventListener("click", e => {
        if(e.target.matches("[data-link]")){
            e.preventDefault();
            navigateTo(e.target.href);
        }
    });

    // 초기 로딩 시에도 라우터 함수를 호출하여 현재 URL에 대응하는 페이지 로드
    router();
});

 

 

아래의 클래스는 라우터를 통해 동적으로 로드되는 각 페이지(컴포넌트)에서 공통적으로 사용되는 메서드와 속성을 정의함

 
// 클래스 정의 및 내보내기
export default class {
    // 생성자 메서드
    constructor(params) {
        // 클래스 인스턴스의 params 속성에 전달받은 매개변수(params) 설정
        this.params = params;

        // 매개변수를 콘솔에 출력
        console.log(this.params);
    }

    // 페이지 제목을 설정하는 메서드
    setTitle(title) {
        document.title = title;
    }

    // 비동기 메서드 (아직 구현되지 않음)
    async fetch(url) {
        return ""; // 아무런 동작을 하지 않고 빈 문자열을 반환
    }

    // 뷰 스크립트를 실행하는 비동기 메서드 (아직 구현되지 않음)
    async executeViewScript() {
        return ""; // 아무런 동작을 하지 않고 빈 문자열을 반환
    }
}

 

 

위의 layout클래스를 상속받은 클래스는 아래처럼 구성됨.

// layout 모듈에서 가져온 클래스를 확장(상속)하는 클래스 정의 및 내보내기
export default class extends layout {
    // 생성자 메서드
    constructor(params) {
        // 부모 클래스의 생성자 호출
        super(params);
        
        // 페이지 제목 설정
        this.setTitle("Home");
    }

    // 비동기 메서드: HTML을 반환하는 메서드
    async getHTML() {
        return `
            <div class="home-background">
                <div class="home-box">
                    <h1>Craft Your <br> Dreams</h1>
                    <h3>인테리어 스타일링과 예상 견적 서비스를 제공합니다.</h3>
                    <div class="button-wrapper">
                        <a href="/design" data-link id="next-btn"> 시작하기 </a>
                    </div>
                </div>
                <div class="home-img">
                </div>
            </div>
        `;
    }

    // 스크립트를 실행하는 메서드
    executeScript() {
        console.log("Hello, This is the Main Page");
    }
}

 

parameter값과 Title을 Submit으로 동적으로 구성함.

 

getHTML메서드를 통해서 뷰를 비동기 함수로 전달한다.

 


위의 구조를 보면

babel과 webpack이 있는데..! 그건 아래글 참고 (--스크랩글)

 

https://seo-tory.tistory.com/74

 

[JS] 웹팩(Webpack)과 바벨(Babel): 바닐라 자바스크립트에 처음부터 적용시켜보기

최근 바닐라 자바스크립트로 과제를 만들 기회가 있었다. 요즘 계속 React를 많이 사용했었기 때문에 JSX의 편리함에 익숙해져있던 편이었지만 다행히도 바닐라 자바스크립트를 사용해서 코딩하

seo-tory.tistory.com


 

함께 참고하면 좋은 블로그 글

 

https://velog.io/@jhyj0521/FE-%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EC%9B%B9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat.-POT-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8

 

[FE] 바닐라 자바스크립트로 웹 컴포넌트 만들기! - feat. 'POT' 프로젝트

최근에 웹 컴포넌트라는 개념을 처음 듣고 관심이 생기게 되었다 😀새로 알게 된 기술을 학습할 때 공식 문서를 참조하여 간단하게 작은 것이라도 만들어 보고자 하는 편인데, 더 좋은 방법은

velog.io

 

강의 : 노마드코더 바닐라 자바스크립트 강의