728x90
반응형
해시 라우터 관리
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" defer src="./src/main.js"></script>
<link rel="stylesheet" href="./src/main.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
MAIN.CSS
body {
height: 3000px;
}
header {
position: fixed;
top: 0;
width: 100%;
background-color: rgba(255,255,255,.5);
}
CORE.JS
// 컴포넌트, 라우터, 스토어(컴포넌트와 컴포넌트의 데이터 통신 기능) 기능 포함
/* =========== Component ============ */
// tagName을 받거나, el 속성에 요소를 메모리 상에만 하나 추가하고,
// 사용되는 부분에서 정의되는 render 함수 부분을 실행
export class Component {
// payload : App.js에서 요소 생성에서 필요한 태그 인수인데, 객체 데이터를 payload에 저장
constructor(payload = {}) {
// 객체 구조 분해 할당
// payload 객체 데이터의 tagName 속성에서 데이터를 꺼냄
const {
tagName = 'div',
state = {},
props = {}
} = payload
// this가 붙어있는 경우, 클래스 내부에서 만들어지는 모든 메소드 안에서
// this 키워드로 참조해서 사용 가능
this.el = document.createElement(tagName)
this.state = state
this.props = props
this.render() // 최초 1번만 호출
}
// 컴포넌트 클래스를 App.js, 다른 js 파일에서 확장해서 사용할 때만 동작
render() {
}
}
/* =========== Router ============ */
// 페이지
function routeRender(routes) {
if(!location.hash){
// replaceState : 히스토리 내역에 기록을 남기지 않고, 페이지 이동
history.replaceState(null, '', '/#/')
}
const routerView = document.querySelector('router-view')
// http://localhost:1234/#/about?name=test
// hash : #/about?name=test
// ? 기준으로 쿼리 스트링과 hash 부분을 구분해야함
const [hash, qeuryString = ''] = location.hash.split('?')
// a=123&b=456
// ['a=123', 'b=456']
const query = qeuryString
.split('&')
.reduce((acc, cur)=>{
const [key, value] = cur.split('=')
acc[key] = value
return acc
}, {})
history.replaceState(query, '')
const currentRoute = routes.find(route => {
return new RegExp(`${route.path}/?$`).test(hash)
})
routerView.innerHTML = ''
routerView.append(new currentRoute.component().el)
// 모든 기능 실행 후, 페이지 최상단 이동
window.scrollTo(0,0)
}
export function createRouter(routes) {
return function () {
window.addEventListener('popstate', () => {
routeRender(routes)
})
routeRender(routes)
}
}
HEADER.JS
import { Component } from "../core/core.js";
export default class Header extends Component {
constructor() {
super({
tagName : 'header'
})
}
render() {
this.el.innerHTML = /* html */ `
<a href="#/">Main!</a>
<a href="#/about">About!</a>
`
}
}
APP.JS
import { Component } from "./core/core.js";
import Header from './components/Header.js'
export default class App extends Component {
render() {
const routerView = document.createElement('router-view')
this.el.append (
new Header().el,
routerView
)
}
}
INDEX.JS
import { createRouter } from '../core/core.js'
import Home from './Home'
import About from './About'
// 배열 데이터를 옵션으로 받고, 객체 데이터에 path 속성을 통해
// 현재 페이지의 해시 경로와 일치시켜줄 문자를 작성
export default createRouter([
{path:'#/', component: Home},
{path:'#/about', component: About}
])
HOME.JS
import { Component } from "../core/core.js";
export default class Home extends Component {
render() {
this.el.innerHTML = /*html*/ `
<h1>Home Page!</h1>
`
}
}
ABOUT.JS
import { Component } from "../core/core.js";
export default class About extends Component {
render() {
const {a, b, c} = history.state
this.el.innerHTML = /*html*/ `
<h1>About Page!</h1>
<h2>${a}</h2>
<h2>${b}</h2>
<h2>${c}</h2>
`
}
}
728x90
반응형
'JS, TS' 카테고리의 다른 글
[TS] 기본 문법 1 (1) | 2024.01.22 |
---|---|
[JS] 컴포넌트 - 상태관리(스토어) (0) | 2024.01.17 |
[JS] 컴포넌트 (0) | 2024.01.16 |
[JS] 정규표현식 (0) | 2024.01.16 |
[JS] 심화 학습 (0) | 2024.01.15 |