Router

jangws·2022년 4월 7일
1


바닐라 자바스크립트를 이용하여 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 속성에 해당 상태의 복제본이 담겨 있다.
    1. title : (현재 대부분의 브라우저가 무시) 그냥 빈 문자열 지정
    2. url : 새로운 세션 기록 항목의 URL. 상대 URL을 지정할 수 있으며, 이 땐 현재 URL을 기준으로 사용합니다.
      • pushState() 호출 이후에 브라우저는 주어진 URL로 탐색하 않습니다. 그러나 이후, 예컨대 브라우저를 재시작할 경우 탐색을 시도할 수도 있습니다. 상대 URL을 지정할 수 있으며, 이 땐 현재 URL을 기준으로 사용합니다. 새로운 URL은 현재 URL과 같은 출처를 가져야 하며, 그렇지 않을 경우 예외가 발생합니다. 지정하지 않은 경우 문서의 현재 URL을 사용합니다.

popState 이벤트

  • popstate
    - popstate 이벤트는 history.pushState() 또는 history.replaceState()를 통해 발생하는 것이 아니라, 같은 document에서 두 히스토리 엔트리 간의 이동이 있을 때만 발생한다.
    - 만약 활성화된 엔트리가 history.pushState() 메서드나 history.replaceState() 메서드에 의해 생성되면, popstate 이벤트의 state 속성히스토리 엔트리 state 객체의 복사본을 갖게 됩니다.
window.onpopstate = funcRef;

0개의 댓글