프레임워크 없이 순수 바닐라JS로 SPA(Single Page Application)을 개발해보자.
포스팅 된 프로젝트는 아래 깃헙(github)에서 확인하실 수 있습니다.
https://github.com/awesome-sh/vanila-spa
주요 기능
SPA의 주요 특징 중 하나가 Routing 처리라고 할 수 있습니다. 메뉴이동 시, 페이지 새로고침이 발생하지 않으며 다른 페이지가 렌더링 되는것을 볼 수 있습니다. 이 기능을 구현하기 위해 브라우저 API를 활용하여 Custom Routing을 만들어 처리를 할 수 있습니다.
Default HTML
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vanila JS - SPA</title>
</head>
<body>
<nav>
<a href="/" data-link>Dashboard</a>
<a href="/about" data-link>About</a>
<a href="/posts" data-link>Posts</a>
<a href="/contact" data-link>Contact</a>
</nav>
<div id="app"></div>
<script type="module" src="/src/js/index.js"></script>
</body>
</html>
location.pathname을 이용하여 Route Matching을 진행합니다.
pathname과 우리가 만들어 놓은 Routes 배열의 객체들을 비교하여 일치하는 path를 찾아냅니다.
// index.js
/**
* Custom Router
*/
const router = async () => {
// Routes Array
const routes = [
{ path: '/', view: Dashboard },
{ path: '/about', view: About },
{ path: '/posts', view: Posts },
{ path: '/contact', view: Contact }
]
// Make isMatch: boolean
const routerMatchs = routes.map(route => {
return {
route,
isMatch: location.pathname === route.path
}
})
// Find True Match
let match = routerMatchs.find(routerMatch => routerMatch.isMatch)
// Not Match : 매치된 Route가 없으면 '/' Route로 지정
if(!match) {
match = { route: routes[0], isMatch: true }
}
const view = new match.route.view()
document.querySelector('#app').innerHTML = await view.getHtml()
}
data-* Attribute를 활용하여 A 태그 이벤트 중단 후 우리가 만들어놓은 Custom Route로 보내기
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if(e.target.matches("[data-link]")) {
e.preventDefault()
navigateTo(e.target.href)
}
})
router()
})
실제로 페이지가 이동된 것 처럼 pushState, popstate를 이용한 페이지 이동 및 유지기능 (뒤로가기,앞으로가기 등)
// index.js
const navigateTo = url => {
history.pushState(null, null, url)
router()
}
window.addEventListener("popstate", router)
여기서 중요한 부분은 pushState와 popstate의 역할입니다.
해당 이벤트가 어떤일을 하는지는 여기 에서 확인해주세요
Abstract Class를 활용한 페이지 생성
Default Page Class를 생성해두고 페이지 생성 시,
추상클래스를 상속받아 페이지를 구성해주는 방법으로 Class를 활용할 수 있습니다.
// Abstract Class (Page.js)
export default class {
constructor() {
}
setTitle(title) {
document.title = title
}
async getHtml() {
return "";
}
}
// Dashboard.js (Page)
import Page from './Page.js'
export default class extends Page {
constructor() {
super()
this.setTitle("Dashboard")
}
async getHtml() {
return `
<h3>Dashboard</h3>
`
}
}
이렇게 간단하게 SPA 구현에 가장 중요한 Routing 처리방법에 대해 알아보았습니다.
다음 포스팅에서는 URL Parameters 처리에 대한 부분을 포스팅 하겠습니다.
React, Vue, Angular 등 고~~오급 개발자분들이 만들어놓으신 프레임워크만 쓰다보니
스스로 미니 프레임워크를 직접 개발해보는것이 많은 도움이 될 것 같아 정리해보게 되었습니다.
Ref. dcode
'Front > JavaScript' 카테고리의 다른 글
트리 쉐이킹 (Tree Shaking) 이란 무엇인가 (0) | 2022.01.12 |
---|---|
이벤트 루프 (Event Loop) 정확히 알기 (2) (0) | 2021.10.17 |
이벤트 루프 (Event Loop) 정확히 알기 (1) (0) | 2021.10.15 |
[Javascript] 호이스팅(Hoisting)에 대해 정리 (0) | 2021.10.07 |
[JavaScript] Generator Function 이해하기 (0) | 2020.05.25 |
댓글