- 핵심은 html의 <div class="root"></div> 태그에 코드를 넣고 빼는 것입니다.
- 뒤로가기를 위해 기록을 남깁니다.
구현
- vallina-spa-test와 같은 폴더를 생성합니다(이름은 마음대로 선택할 수 있습니다)
- 아래와 같은 폴더구조를 만듭니다.
- index.html에 아래의 코드를 입력합니다.
script 태그에 type="module"을 꼭 넣어줍니다.
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
<div class="root"></div>
<script type="module" src="./index.js"></script>
</body>
</html>
- index.js에 아래와 같이 코드를 입력합니다.
import App from './app.js';
const config = {
el: '#root'
}
new App({ el: '#root' }).setup()
- app.js 파일을 만들고 아래와 같이 입력합니다.
import { About, Home } from './pages/index.js';
import { Router } from './utils/index.js';
export default class App {
constructor(props) {
this.props = props;
}
setup() {
const { el } = this.props;
const router = new Router({
'/': Home,
'/about': About
});
router.init(el);
}
}
- pages/about.js파일에 아래와 같이 입력합니다.
export default class About {
constructor() {
}
render() {
return '<a href="/">Home</a>'
}
}
- pages/home.js파일에 아래와 같이 입력합니다.
export default class Home {
constructor() {
}
render() {
return `<a href="/about">About</a>`
}
}
- pages/index.js파일에 아래와 같이 입력합니다.
export { default as About } from './about.js'
export { default as Home } from './home.js'
- utils/index.js에 아래와 같이 입력합니다.
export { default as Router } from './router.js';
- utils/router.js에 아래와 같이 입력합니다.
export default class Router {
constructor(routes) {
if (!routes) {
console.error('Can not initialize routes, need routes!');
}
this.routes = routes
}
init(rootElementId) {
if (!rootElementId) {
console.error('Can not initialize Route, not define rootElementId');
return;
}
this.rootElementId = rootElementId;
this.routing(window.location.pathname);
window.addEventListener('click', (e) => {
if (e.target.closest('a')) {
e.preventDefault();
this.routePush(e.target.closest('a').href);
}
})
window.onpopstate = () => this.routing(window.location.pathname)
}
routePush(pathname) {
window.history.pushState({}, null, pathname);
this.routing(window.location.pathname)
}
routing(pathname) {
let page = "";
if (this.routes[pathname]) {
const component = new this.routes[pathname]();
page = component.render()
}
if (page) {
this.render(page)
}
}
render(page) {
const rootElement = document.querySelector(this.rootElementId)
rootElement.innerHTML = page
}
}
여기에서 window.onpopstate와 window.history.pushState가 중요하다.