[#2] Vanilla JavaScript로 SPA 구현하기 (No Frameworks)

nemo·2022년 2월 28일
5

JavaScript

목록 보기
10/23

👉 [#1] Vanilla JavaScript로 SPA 구현하기



URL에 파라미터 추가하기

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)

1개의 댓글

comment-user-thumbnail
2023년 2월 15일

안녕하세요 뭐하나만 질문 드려도 될까요? 제가 보다가보다가 도저히 이해가 안가는 부분이 const view = new match.route.view() 이부분인데요, 꼭 new 생성자 함수를 써야하는 이유가 뭐죠?

답글 달기