👉 [#1] Vanilla JavaScript로 SPA 구현하기
Posts 페이지에 파라미터를 추가해보자.
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import NotFound from "./views/NotFound.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]];
}));
};
const navigateTo = url => {
history.pushState(null, null, url);
router();
}
const router = async () => {
const routes = [
{ path: "/", view: Dashboard },
{ path: "/posts", view: Posts },
// 파라미터가 추가됐을 경우 route 추가
{ path: "/posts/:id/:something", view: Posts },
{ path: "/settings", view: Settings },
{ path: "/404", view: NotFound },
];
const potentialMatches = routes.map(route => {
return {
route: route,
// result로 변경하고 정규식과 일치하는 pathname을 담는다
result: location.pathname.match(pathToRegex(route.path))
};
});
// 정규식과 일치하는 pathname이 null이 아닌 경우 담기
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
// 없는 페이지일 때, 404 페이지로 이동하고 result에는 해당 pathname 담기
if (!match) {
match = {
route: routes[routes.length - 1],
result: [location.pathname]
}
}
// match 정보를 getParams에 보내 배열로 출력해서 view에 담기
const view = new match.route.view(getParams(match));
document.querySelector('#app').innerHTML = await view.getHtml();
};
window.addEventListener("popstate", router);
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
});
router();
});
(views/AbstractView.js)
export default class {
// params
constructor(params) {
this.params = params;
console.log(this.params)
}
setTitle(title) {
document.title = title;
}
async getHtml() {
return "";
}
}
(views/Posts.js)
import AbstractView from "./AbstractView.js";
export default class extends AbstractView {
// params 값 전달받기
constructor(params) {
super(params);
this.setTitle("Posts");
}
async getHtml() {
return `
<h1>Posts</h1>
<p>You're viewing the posts!</p>
`;
}
}
파라미터 추가 작업은 정규식부터 좀 난해하다. 차분히 뜯어봐야 할 듯.
📎 Adding Client Side URL Params - Build a Single Page Application with JavaScript (No Frameworks)
안녕하세요 뭐하나만 질문 드려도 될까요? 제가 보다가보다가 도저히 이해가 안가는 부분이 const view = new match.route.view() 이부분인데요, 꼭 new 생성자 함수를 써야하는 이유가 뭐죠?