티스토리 뷰
해당 기능을 구현 시 동작: 뒤로가기 시 실제 URL은 변경되지 않고, 렌더링을 통해 뒤로가는 모습처럼 보이도록 가능하다.
적용 가능한 상황: 순수 JS를 이용해서 SPA를 만드는 경우
이용 기능: window.history
알아두면 좋은 내용
History.length 읽기 전용
현재 페이지를 포함해, 세션 기록의 길이를 나타내는 정수를 반환합니다
=> 실제로 경험해보니, 브라우저 처음에 들어가는 경우, length가 3이다.
=> 하나씩 증가하는데, 뒤로 간다고 해당 length가 줄어들지는 않는다.
=> 결국 초기값만 의미가 있을 뿐, 그 이후 의미가 없는 값으로 생각해야 한다.
해당 값이 읽기 전용인 이유는 브라우저에서 보안상 history 정보를 공유할 수 없기 때문이다.
사용하는 기술 CookBook
1. history.back();
우리가 아는 뒤로가기인데, 뒤로가기를 이벤트 리스너를 이용하게 되면, 조금 다른 개념이 되는 듯하다.
경험상으로는 history.state란 값이 null이면 기존에 알던 back()이었고, 다른 값이 들어가 있다면 재정의된 이벤트로 움직인다.
추가적으로 브라우저에서 제공되는 뒤로가기버튼 이나 모바일에서 브라우저를 키고 시스템에서 뒤로가기 버튼을 클릭 시 발생되는 이벤트가 있다.
이 모든 이벤트를 history.back()과 동일하게 맞추려면 history.state가 null이 아니어야 한다.
즉, 해당 history.state를 이용해서 진짜 뒤로가기 기능을 이용할 수 있게 된다.
2. history.go();
ios 15? 14? 정도의 사파리에서 back()이 제대로 동작 안 하는 경우도 존재한다. 그런 경우 go(-2)를 이용해서 해결이 가능할 수도 있다. 이 경우 정말 그렇게 동작하는지 한번 확인하고 적용하길 추천한다..
3.history.pushState()
히스토리 내역을 직접 넣을 수 있게 해준다.
4.history.replaceState()
앞에서 이야기하였던 history.state를 null로 바꾸거나 다른 값으로 바꿀 때 이용 가능하다.
5. addEventListener("popstate", (event) => {});
뒤로가기 이벤트를 감지해서 재정의할 수 있는 리스너다.
각 상태를 정의해서 해당 이벤트를 정의해서 사용해보자.
관련 문서
https://developer.mozilla.org/ko/docs/Web/API/History
https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event
History - Web API | MDN
History 인터페이스는 브라우저의 세션 기록, 즉 현재 페이지를 불러온 탭 또는 프레임의 방문 기록을 조작할 수 있는 방법을 제공합니다.
developer.mozilla.org
LocalStorage와 SessionStorage
Js에서 우린 뒤로가기를 재정의를 하려고 하니, 현재 데이터를 어딘가 저장해두고 페이지를 재로딩 시 동일한 화면으로 그려줘야 한다.
브라우저에는 LocalStorage가 있는데 이건 브라우저에서 동일한 URL을 들어갔을 때 데이터를 공유한다.
SessionStorage는 브라우저 탭을 기준으로 동일한 URL인 경우 공유한다.
탭과 브라우저는 큰 차이를 가진다. 예를 들어 웹뷰로 제작 중인 페이지를 띄운다고 했을 때 LocalStorage를 쓴다면 현재 웹뷰를 닫고 새로운 웹뷰를 띄운다고 한들 이전에 봤던 화면이 나오게 된다.
그래서 탭 기준으로 데이터를 저장하는 SessionStorage를 이용해야 한다.
Vaillna Js의 상태 관리
React 상태 관리 라이브러리를 사용하면 해당 값은 이전에 언급한 Storage에 저장됨을 확인할 수 있다.
우리도 동일하게 이 저장소를 이용하고 있는데 React와 다른 점은 무엇일까?
React에서 상태 관리를 이용한 편리한 UI 재렌더링이다. vaillna Js에선 직접 렌더링을 해야하기 때문에 상태 관리를 통한 렌더링이 어렵다.
직접 UI를 렌더링해줘야 하기 때문에 실수도 많아진다.
조심해야 하는 부분이다...
실제 적용해보기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.page {
display: none;
transition: opacity 0.5s ease;
opacity: 0;
width: 100%;
height: 100vh;
background-color: beige !important;
}
.page.active {
display: block;
opacity: 1;
}
</style>
</head>
<body>
<div class="page active" id="page1">
PAGE 1
</div>
<div class="page" id="page2">
PAGE 2
</div>
<div class="page" id="page3">
PAGE 3
</div>
<script>
const searchParams = new URLSearchParams(window.location.search);
const pages = document.querySelectorAll('.page');
let currentPage = 0;
if(searchParams.get('page') == null) {
pages[currentPage].classList.add('active');
} else if(searchParams.get('page') == 1) {
document.getElementById('page1').classList.add('active');
// history.pushState({ page: 0 }, '', `?page=${1}`);
} else if(searchParams.get('page') == '2') {
document.getElementById('page1').classList.remove('active');
document.getElementById('page2').classList.add('active');
history.pushState({ page: 1 }, '', `?page=${2}`);
} else if(searchParams.get('page') == 3) {
document.getElementById('page1').classList.remove('active');
document.getElementById('page3').classList.add('active');
history.pushState({ page: 2 }, '', `?page=${3}`);
}
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') {
pages[currentPage].classList.remove('active');
currentPage = (currentPage + 1) % pages.length;
pages[currentPage].classList.add('active');
} else if (e.key === 'ArrowLeft') {
pages[currentPage].classList.remove('active');
currentPage = (currentPage - 1 + pages.length) % pages.length;
pages[currentPage].classList.add('active');
}
history.pushState({ page: currentPage }, '', `?page=${currentPage + 1}`);
});
window.addEventListener('popstate', (e) => {
pages[currentPage].classList.remove('active');
currentPage = e.state.page;
pages[currentPage].classList.add('active');
});
</script>
</body>
</html>'코딩 관련 > 자바스크립트' 카테고리의 다른 글
| Zustand, Vanilla js에서 사용하여 데이터에 집중하자 (0) | 2024.07.26 |
|---|---|
| Youtube Ifram을 하는데 썸네일, 또는 버튼을 바꾸고 싶은 경우 (0) | 2024.06.28 |
| Currying/Partial Application 인수를 하나를 받아, 복잡도를 낮추는 방법 (0) | 2023.10.19 |
| generator function (0) | 2023.10.19 |
| getDay(), getDate() (0) | 2023.10.19 |