JavaScript
[JavaScript]바닐라자바스크립트 컴포넌트생성하기
hans-j
2023. 12. 5. 10:56
// 페이지(컴포넌트) 임포트
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
함께 참고하면 좋은 블로그 글
강의 : 노마드코더 바닐라 자바스크립트 강의