먼저 예제를 위해 필요한 파일들을 생성해보자.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script src="src/index.js">
</script>
</body>
</html>
App.js
export default function App({ $parent }) {
this.render = () => {};
this.render();
}
index.js
import App from "./App.js";
new App({ $parent: document.querySelector("div#app") });
페이지는 메인 페이지, 상세 페이지, 404 페이지 세개를 구현한다.
페이지는 모두 다음과 같은 형식을 갖추고 있다.
export default function Page({ $parent }) {
const $page = document.createElement("div");
$parent.appendChild($page);
this.render = () => {
$page.innerHTML = `
<h1>페이지입니다.</h1>
`;
};
this.render();
}
URL에 대한 정보를 받기 위해 location
Web API의 pathname
프로퍼티를 사용한다.
App.js
import MainPage from "./pages/MainPage";
import DetailPage from "./pages/DetailPage";
import NotFoundPage from "./pages/NotFoundPage";
...
this.render = () => {
const { pathname } = location;
if (pathname === '/') {
new MainPage({ $parent });
} else if (pathname === '/detail') {
new DetailPage({ $parent });
} else {
new NotFoundPage({ $parent });
}
};
...
이제 URL에 따라 해당하는 페이지를 불러온다. 하지만 여기에는 몇가지 문제점이 있다.
해당 기능을 구현하기 위해 Router를 구현해보자.
History.pushState
Router 구현에 앞서 History Web API에 대해 알 필요가 있다. MDN 문서에서 History Web API를 다음과 같이 정의하고 있다.
History
인터페이스는 브라우저의 세션 기록, 즉 현재 페이지를 불러온 탭 또는 프레임의 방문 기록을 조작할 수 있는 방법을 제공합니다.
History Web API는 다양한 메서드를 제공하는데, 그 중에서 Router 구현에 사용할 메서드는 History.pushState
다.
History.pushState
는 다음과 같이 3개의 매개변수를 가진다.
History.pushState(state, title[, url])
popstate
이벤트가 발생하는데, 이때 이벤트 객체의 state
속성으로 사용될 객체의 원본이 된다.window.location
또한 새로운 세션 기록 항목을 생성한다는 점에서 History.pushState
와 비슷하지만, History.pushState
는 다음과 같은 장점을 가진다.
window.location
은 해시(#
)가 아닌 경우 다른 문서로 이동한다.window.location
은 해시가 변경된 경우에만(hashchange
이벤트 발생 시) 새로운 세션 기록 항목을 생성한다.