router.js
import DetailPage from "./pages/DetailPage";
import MainPage from "./pages/MainPage";
import NotFoundPage from "./pages/NotFoundPage";
class Router {
constructor(routes) {
this.routes = routes;
this.routeList = Object.keys(this.routes);
}
// 경로가 바뀔 때 실행될 리스너 함수를 등록하는 메서드
registerListener(listener) {
window.addEventListener("changePath", listener);
}
// 라우터를 통한 URL 이동 시에 URL의 변경을 애플리케이션에 알리는 임의의 이벤트 'changePath' 이벤트를 발생시키는 메서드
go(path) {
history.pushState(null, null, path);
window.dispatchEvent(new Event("changePath"));
}
}
const routes = {
"/": MainPage,
"/detail": DetailPage,
"/404": NotFoundPage
};
const router = new Router(routes);
export default router;
Router를 App에 적용시켜보자.
App.js
import router from "./router";
export default function App({ $parent }) {
// URL 변경 시에 애플리케이션 내부 DOM Element를 초기화
this.initApp = () => {
$parent.innerHTML = "";
};
this.render = () => {
this.initApp(); // 애플리케이션 내부 DOM Element를 초기화
const { pathname } = location;
// 변경된 URL이 라우터에 등록된 URL이 아닐 경우
if (!router.routeList.includes(pathname)) {
// 404 페이지로 이동
history.pushState(null, null, "/404");
new router.routes["/404"]({ $parent });
} else {
// 변경된 URL이 라우터에 등록된 URL일 경우 해당 페이지로 이동
new router.routes[pathname]({ $parent });
}
};
// 라우터를 통한 페이지 이동 시에 애플리케이션이 렌더링 되도록 'changePath' 이벤트에 렌더링 함수를 리스너 함수로 등록
router.registerListener(this.render);
this.render();
}
이제 Router를 통한 페이지 이동을 테스트해보자. 메인 페이지와 상세 페이지에 각각 다른 페이지로 이동하는 버튼을 추가했다.
MainPage.js
import router from "../router";
export default function MainPage({ $parent }) {
const $page = document.createElement("div");
$parent.appendChild($page);
this.render = () => {
$page.innerHTML = `
<h1>메인 페이지입니다.</h1>
<button id="to-detail-btn">상세 페이지로</button>
`;
document
.querySelector("button#to-detail-btn")
.addEventListener("click", (e) => {
router.go("/detail");
});
};
this.render();
}
DetailPage.js
import router from "../router";
export default function DetailPage({ $parent }) {
const $page = document.createElement("div");
$parent.appendChild($page);
this.render = () => {
$page.innerHTML = `
<h1>상세 페이지입니다.</h1>
<button id="to-main-btn">메인 페이지로</button>
`;
document
.querySelector("button#to-main-btn")
.addEventListener("click", (e) => {
router.go("/");
});
};
this.render();
}
History.pushState
를 활용하여 SPA Framework의 Router를 구현했다. 예제를 통해 제대로 작동하는지 확인해보자.