프로젝트 설정
우리에게 필요한 것은 html과 js 파일이 전부입니다.기본적인 html 파일을 만들도록 하겠습니다.
index.html
<!DOCTYPE html>
<html>
<body>
<main></main>
</body>
</html>
index.html 파일을 열 때 내부 콘텐츠를 설정하도록 하겠습니다.
index.js
window.onload = () => {
const main = document.querySelector("main");
main.innerHTML = "<div>js loaded</div>";
};
<script>
태그를 사용하여 실행해 주도록 하겠습니다.index.html
<!DOCTYPE html>
<html>
<body>
<script src="./index.js"></a>
<main></main>
</body>
</html>
index.js
window.onload = () => {
const main = document.querySelector("main");
main.innerHTML = "<div>js loaded</div>";
};
<a>
태그와 window.location.href 값을 변경하는 방법을 통해 이동을 할 수 있지만, 페이지 자체를 새로 불러오기 때문에 같은 어플리케이션이라고 해도 깜박임이 발생하게 됩니다.주소를 이동해도 페이지 자체가 새로고침이 되지 않기 위해서의 pushState 메서드를 사용하여 주소 변경을 할 수 있습니다. window.history
pushState 메서드는 (데이터, 타이틀, URL)의 매개변수를 받도록 되어있습니다.
window.history.pushState(undefined,"타이틀","/some")
주소가 바뀌었다면 이를 감지하여
<main>
태그내의 콘텐츠를 바꾸는것이 라우팅의 원리가 되겠습니다.주소가 변경된 것을 알리고 감지하기 위하여
locationchange
라는를 만들도록 하겠습니다. 커스텀 이벤트index.js
window.onload = () => {
const main = document.querySelector("main");
const handleLocationChange = (e) => {
console.log("locationchanged");
};
window.addEventListener("locationchange", handleLocationChange);
main.innerHTML = "<div>js loaded</div>";
};
index.js
window.onload = () => {
const main = document.querySelector("main");
const handleLocationChange = (e) => {
console.log("locationchanged");
//* 주소변경
window.history.pushState(undefined, "타이틀", "/some");
};
//* locationchange 이벤트리스너
window.addEventListener("locationchange", handleLocationChange);
main.innerHTML = "<div><button type='button'>move to /some</button></div>";
const button = document.querySelector("button");
button.addEventListener("click", () => {
const locationChangeEvent = new CustomEvent("locationchange", {
composed: true, //웹 컴포넌트라면 넣어주세요
});
//* 주소변경 이벤트 Dispatch
window.dispatchEvent(locationChangeEvent);
});
};
locationchange
이벤트가 항상 같은 주소로 이동하는 것은 아니기에 변경할 주소를 인자로 받을 수 있도록 하도록 하겠습니다.커스텀 이벤트를 생성할 때에 detail에 값을 주어 원하는 변수를 전달할 수 있습니다.
index.js
window.onload = () => {
const main = document.querySelector("main");
const handleLocationChange = (e) => {
const { href } = e.detail;
console.log(href);
//* 주소변경
window.history.pushState(undefined, "타이틀", href);
};
//* locationchange 이벤트리스너
window.addEventListener("locationchange", handleLocationChange);
main.innerHTML = "<div><button type='button'>move to /some</button></div>";
const button = document.querySelector("button");
button.addEventListener("click", () => {
const locationChangeEvent = new CustomEvent("locationchange", {
composed: true,
detail: { href: "some" },
});
//* 주소변경 이벤트 Dispatch
window.dispatchEvent(locationChangeEvent);
});
};
window.location.pathname
을 사용하여 라우팅 경로를 받아오도록 합니다. pathname을 사용하는 이유는 "/some? page=1"처럼 쿼리 값이 있을 때 쿼리 값을 제외한 경로를 받을 수 있기 때문입니다.index.js
//* 경로에 맞는 콘텐츠 렌더
const renderContents = () => {
const { pathname } = window.location;
switch (pathname) {
case "/some":
main.innerHTML = "<div>some Contents</div>";
break;
default:
main.innerHTML = "<div>404</div>";
}
};
const handleLocationChange = (e) => {
const { href } = e.detail;
//* 주소변경
window.history.pushState(undefined, "타이틀", href);
//* 콘텐츠 렌더링
renderContents();
};
locationchange
커스텀 이벤트를 통해 라우팅을 하는데 성공했지만, 뒤로 가기 혹은 앞으로 가기를 할 때 주소는 이동하지만 콘텐츠가 바뀌지 않는 것을 볼 수 있습니다.이를 위해 뒤로 가기 및 앞으로가기 이벤트를 감지하는이벤트를 이용하여 변경된 주소로 콘텐츠를 변경해 주도록 하겠습니다. popstate
index.js
window.addEventListener("popstate", () => {
renderContents();
});
띠라서 주소이동시에 같은경로라면 이동하지 않도록 작업을하도록 하겠습니다.
index.js
button.addEventListener("click", () => {
const targetUrl = "some?foo=bar";
const { pathname } = window.location;
//* 같은 URL 은 스택에 추가하지 않는다
if (targetUrl === pathname) {
return;
}
const locationChangeEvent = new CustomEvent("locationchange", {
composed: true,
detail: { href: "some" },
});
//* 주소변경 이벤트 Dispatch
window.dispatchEvent(locationChangeEvent);
});
앞에서 다룬 내용을에 예제를 통해 올리도록 하겠습니다. 깃허브
도움이 되었다면 좋겠네요ㅎㅎ
*이 블로그에서 사용한도 첨부하도록 하겠습니다. lit-html을 사용한 라우터