Router

유섭·2022년 6월 19일
0

자바스크립트

목록 보기
1/3
post-thumbnail

Vanilla JavaScript로 SPA(Single Page Application) 구현하기

SPA의 Routing은 history, hash를 통해 구현 가능하다.

각 방법에는 장단점이 있다.

history

Advantages

  • URL형태가 깔끔하다.
  • 검색엔진 최적화에 유리하다.
  • 대부분의 프레임워크(Angular, React...) 및 최신 개발서버(serve in Angular, React...) 등에서 해당 기능을 제공한다.

hash

Advantages

  • 해시 이후 경로 조각을 별도의 페이지로 간주하지 않으며, 새로고침 하면 index.html이 reload 되어 단일 페이지 앱에 적합하다.

  • 해시가 정의된 링크는 페이지 reload가 발생하지 않으므로 보다 안전하다.

  • API와 프론트엔드 요청을 구별하기 쉽다.

Disadvantages

  • 검색엔진 최적화에 적합하지 않다.
  • #이 붙기때문에 깔끔하지 않다.

자세한 내용은 Using Hashed vs Non-Hashed URL Path in SPA 링크를 참고하면 좋을거 같다.

해당 블로그에서는 history (Non-Hashed) 방법을 사용했다.

router.js

import { $ } from './util/util.js';
import Home from './pages/Home.js';
import Life from './pages/Life.js';
import Trip from './pages/Trip.js';

const router = async () => {
  const routes = [
    { path: '/', view: Home },
    { path: '/life', view: Life },
    { path: '/trip', view: Trip },
  ];


  // routes 목록에서 현재 경로와 path가 일치하는 객체를 할당하여 해당 객체의 컴포넌트 Class를 생성한다.
  let match = routes.find(route => route.path === location.pathname);
  if (match) return match.view;
  else new NotFound($('#root'));
};
export default router;

app.js

import { $ } from './util/util.js';
import Components from './core/Components.js';
import router from './router.js';


export default class App extends Components {
  constructor(props) {
    super(props);
  }

  template() {
    return `
      <div class="container">
		...
        <section id="app"></section>
      </div>
    `;
  }

  async componentDidMount() {
    // 라우터를 실행시켜 현재 경로에 맞는 컴포넌트 클래스를 반환받은 후
    // 해당 클래스 인스턴스를 생성하여 태그에 할당한다.
    const view = await router();
    view && new view($('#app'));
	...
  }
}

아래는 사용자가 Nav 아이템을 클릭하여 페이지를 이동시키는 컴포넌트 클래스 예시이다.

...
	  async componentDidMount() {
      // history에서 항목을 pop하는 경우 (뒤로가기 버튼 클릭시) 처리
    window.onpopstate = async () => {
    	// 현재 경로를 다시 읽고 app 태그에 경로에 맞는 클래스의 template을 넣는다.
      const view = await router();
      view && new view($('#app'));
    };

	// menu ul 태그에 이벤트 위임을 사용하여 클릭 이벤트를 등록한다.
    $('.category_menu_ul').addEventListener('click', async event => {
      console.log(event);
      event.preventDefault();
      
      // closest를 사용하여 타겟과 가까운 li를 찾아 data-cm 속성을 읽고
      // 해당 속성 경로를 history에 push한다.
      const { cm } = event.target.closest('li').dataset;
      const { pathname } = window.location;
      console.log(pathname);
      if (pathname === '/' + cm || (pathname === '/' && cm === 'home')) return;
      console.log(cm);
      window.history.pushState(null, '', cm === 'home' ? '/' : cm);

	  // 해당 속성 경로를 Push한 뒤 라우터를 실행한다.
      const view = await router();
      view && new view($('#app'));
    });
  }
...

0개의 댓글

관련 채용 정보