JS로 SPA를 위한 간단한 Router 구현

Marco·2022년 4월 7일
1

Javascript TIL

목록 보기
12/12
post-thumbnail


바닐라 자바스크립트를 이용하여 SPA를 위한 간단한 Router를 만들어보고, 관련 개념을 정리하자.
데모페이지와 코드샌드박스 소스코드 주소는 아래와 같다.

DemoPage

codesandbox

html은 다음과 같다. 앵커태그들을 만들고 변경된 html이 주입될 div를 만든다.

// index.html
<!DOCTYPE html>
<html>
  <head>
    <title>SPA Router - Vanila JavaScript</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="root">
      <nav>
        <a href="/" id="homeRoute">Home</a>
        <a href="/about" id="aboutRoute">About</a>
        <a href="/blog" id="blogRoute">Blog</a>
      </nav>
      <div id="contents"></div>
    </div>

    <script src="router.js"></script>
  </body>
</html>

js는 다음과 같다.

  • routes 객체를 만든다.
  • url 변경이 있을 때마다 호출될 getRouteHtml 함수를 만들었고 이 함수는 fetch를 통해 받은 response의 text()를 DOM에 삽입한다.
  • handleRoute 함수는 앵커태그 클릭 시 호출된다. 앵커의 href값을 history.pushState 메서드의 세 번째 인수(url)에 전달하여 브라우저의 URL을 업데이트한다.
// route.js

const routes = {
  404: "/pages/404.html",
  "/": "/pages/index.html",
  "/about": "/pages/about.html",
  "/blog": "/pages/blog.html",
};

const getRouteHtml = async () => {
  const path = window.location.pathname;
  const route = routes[path] || routes[404];
  const $contents = document.getElementById("contents");
  await fetch(route)
    .then(response => {
      return response.text();
    })
    .then(text => {
      $contents.innerHTML = text;
    });
};

const handleRoute = event => {
  event = event || window.event;
  event.preventDefault(); // anchor 태그의 기본동작인 링크 대상으로 이동하는 행동을 방지한다.
  window.history.pushState({}, "", event.target.href); 
  getRouteHtml();
};

window.onpopstate = getRouteHtml;

getRouteHtml();

document.getElementById("homeRoute").addEventListener("click", handleRoute);
document.getElementById("aboutRoute").addEventListener("click", handleRoute);
document.getElementById("blogRoute").addEventListener("click", handleRoute);

fetch

handleLocation 함수 내에서 route를 fetch하여 받은 data는 프로미스이고 콘솔로 찍으면 아래와 같다.

fetch의 Body

Body 믹스인은 Request나 Response (en-US)에 구현되어, 콘텐츠를 추출하기 위해 아래의 메서드가 정의되어 있다. 이러한 메서드들은 전부 최종적으로 요청으로 반환된 값을 내장하고 있는 promise를 반환한다.

  • arrayBuffer()
  • blob()
  • json()
  • text() : Response 인터페이스의 text() 메서드는 Response Stream을 가져와 완료할 때까지 읽는다. String으로 Resolve되는 Promise를 반환한다(UTF-8로 디코딩됨).
  • formData()

window.location

Window.location 프로퍼티에 접근하면 읽기 전용인 Location 객체를 얻어올 수 있다. 이는 현재 도큐먼트의 로케이션에 대한 정보를 담고 있다.

윈도우 URL이 바뀔 때마다, window.location을 콘솔로 찍으면 아래와 같은 객체를 확인할 수 있다.

Location 인터페이스

Location 인터페이스는 객체가 연결된 장소(URL)를 표현한다. Location 인터페이스에 변경을 가하면 연결된 객체에도 반영되는데, Document와 Window 인터페이스가 이런 Location을 가지고 있다. 각각 Document.location과 Window.location으로 접근할 수 있다.

location.pathname은 '/' 문자 뒤 URL의 경로를 값으로 하는 DOMString이다.

History 인터페이스

History 인터페이스는 브라우저의 세션 기록, 즉 현재 페이지를 불러온 탭 또는 프레임의 방문 기록을 조작할 수 있는 방법을 제공한다.

메서드로 back(), forward(), go(), pushState(), replaceState()가 있다.

history.pushState()

  • history.pushState() 는 브라우저의 세션 기록 스택에 상태를 추가한다.
history.pushState(state, title[, url]);

매개변수
1. state : 새로운 세션 기록 항목에 연결할 상태 객체. 사용자가 새로운 상태로 이동할 때마다 popstate 이벤트가 발생하는데, 이 때 이벤트 객체의 state 속성에 해당 상태의 복제본이 담겨 있다.
2. title : (현재 대부분의 브라우저가 무시) 그냥 빈 문자열 지정
3. url : 새로운 세션 기록 항목의 URL. 상대 URL을 지정할 수 있으며, 이 땐 현재 URL을 기준으로 사용합니다.

  • pushState() 호출 이후에 브라우저는 주어진 URL로 탐색하지 않는다. 그러나 이후 예컨대 브라우저를 재시작할 경우 탐색을 시도할 수도 있다. 상대 URL을 지정할 수 있으며, 이 땐 현재 URL을 기준으로 사용한다. 새로운 URL은 현재 URL과 같은 출처를 가져야 하며, 그렇지 않을 경우 예외가 발생한다. 지정하지 않은 경우 문서의 현재 URL을 사용한다.

popState 이벤트

popstate 이벤트는 history.pushState() 또는 history.replaceState()를 통해 발생하는 것이 아니라, 같은 document에서 두 히스토리 엔트리 간의 이동이 있을 때만 발생한다.

만약 활성화된 엔트리가 history.pushState() 메서드나 history.replaceState() 메서드에 의해 생성되면, popstate 이벤트의 state 속성히스토리 엔트리 state 객체의 복사본을 갖게 된다.

profile
블로그 이사 🚚 https://wonsss.github.io/

1개의 댓글

comment-user-thumbnail
2023년 4월 4일

안녕하세요~ 각 pages의 html에서만 동작할 수 있도록 자바스크립트를 연동하려면 어떻게 해야되는 지 문의드려도 될까요? 자바스크립트를 root의 index.html에 넣어줘야 동작이 되더라고요.

답글 달기