이 글은 아래 [참고]에 작성한 블로그들을 보고 공부한 내용을 기록한 글입니다.
DOM의 window 객체는 history 객체를 통해 브라우저의 히스토리에 접근할 수 있다.
예를들면 아래와 같이 back()
, forward()
, go()
메서드를 이용하여 브라우저의 이전페이지, 다음페이지 기능을 구현할 수 있다.
// 뒤로가기
window.histroy.back();
// 앞으로가기
window.histroy.forward();
//back()과 동일하게 한 페이지 뒤로 이동
window.history.go(-1);
//forward()와 동일하게 한 페이지 앞으로 이동
window.history.go(1);
// 두 페이지 이전으로 이동
window.history.go(-2);
//length속성을 이용하여 몇페이지가 쌓여있는지 알 수 있다
window.history.length;
//현재페이지를 기준으로 앞, 뒤 페이지가 없다면 1이 출력된다.
history 내역은 하나의 목록이다. 뒤로가기, 앞으로가기는 목록 안에서 이동하는 것이다. 따라서 목록에 새로운 주소를 추가하면 페이지를 이동한 셈이 된다. 그 목록에 주소를 추가하기 위한 메소드가 HTML5에서 생겼는데, 바로 history.pushState()
와 history.replaceState()
이다.
history.pushState({data: 'pushState1'}, '', '/pushState1');
history.replaceState({data: 'replaceState'}, '', '/replace-state');
첫번째 파라미터는 history.state에 기록할 데이터다. 두번째 인자는 바꿀 제목 그리고 세번째 인자는 바뀔 주소이다.
아래의 코드로 공부를 해보자.
<!DOCTYPE html>
<html lang="ko">
<head>
<title>History API Sample</title>
<meta charset="utf-8" />
<style>
section {
margin: 20px 0;
}
</style>
</head>
<body>
<section>
<h2>push state</h2>
<button id="push-state1">pushState1</button>
<button id="push-state2">pushState2</button>
<button id="push-state3">pushState3</button>
</section>
<section>
<h2>replace state</h2>
<button id="replace-state">replaceState</button>
</section>
<section>
<h2>history state</h2>
<span id="state"></span>
</section>
<script>
const currentHistoryState = () => {
document.getElementById("state").innerText = JSON.stringify(
history.state
);
};
currentHistoryState();
// pushState()
document.getElementById("push-state1").addEventListener("click", () => {
history.pushState({ data: "pushState1" }, "", "/push-state1");
currentHistoryState();
});
document.getElementById("push-state2").addEventListener("click", () => {
history.pushState({ data: "pushState2" }, "", "/push-state2");
currentHistoryState();
});
document.getElementById("push-state3").addEventListener("click", () => {
history.pushState({ data: "pushState3" }, "", "/push-state3");
currentHistoryState();
});
// replaceState()
document.getElementById("replace-state").addEventListener("click", () => {
history.replaceState({ data: "replaceState" }, "", "/replace-state");
currentHistoryState();
});
// 브라우저의 뒤로가기 / 앞으로가기를 누르면 history state 값을 확인하여 출력합니다.
window.addEventListener("popstate", () => {
currentHistoryState();
});
</script>
</body>
</html>
코드는 이 👉블로그 의 주인분이 쓰신 코드다.
처음 창을 열었을 땐 아래와 같은 상태가 뜬다
이때 pushState 1, 2, 3을 순서대로 누르면
이렇게 아래와같이 잘 바뀐다. 게다가 뒤로가기가 잘 활성화 되어있다.
그럼 다시 라이브서버를 켜서 replaceState버튼을 눌러보자.
주의깊게 볼 부분: replaceState를 눌렀을 때 url부분과 아래의 history.state
는 잘 변경 되지만, 뒤로가기 버튼이 비활성화 되어있다.
이는, pushState는 주소목록에 새로운 주소를 추가하며, 방금까지 있던 주소를 이전 주소로 두고 새로운 주소로 /pushState 를 추가한 것이다. 그래서 이전 주소가 남아있기 때문에 뒤로가기를 통해 이전 주소로 넘어갈 수 있었다.
하지만 replaceState는 이전 주소를 없애고 바꿀 주소를 넣는다. 즉 새로운 엔트리를 추가하지 않고, 현재의 엔트리 값을 변경하기 때문에 뒤로가기로 이전 URL로 이동할 수 없다.
좀 더 자세히 풀어서 설명하자면,
pushState, replaceState로 주소를 바꾼 후, 뒤로가기나 앞으로가기를 누르면 popstate이벤트가 발생한다. 위의 코드처럼 윈도우에 이벤트 리스너를 연결해 두면 뒤로가기나 앞으로가기를 눌렀을 때 이벤트가 발생한다.
그렇기에 popstate이벤트 발생 후 history.state에 접근하면 이전 state를 가져올 수 있다.따라서 이전 페이지도 그 정보들을 활용하여 다시 렌더링 할 수 있다.
popstate 이벤트는 활성화된 히스토리 엔트리에 변화가 있을 때마다 발생된다. 발생 시 전달되는 state속성은 state object의 사본이 된다. 그로인해, 뒤로 가기의 상황에서 서버 요청 없이 이전 목록의 화면을 보여주는 것과 같은 처리를 할 수 있다.
window.addEventListener("popstate",(e)=>{
let copyState=e.state;
output.innerHTML=copyState.content
})
주의할 점은 history.pushState()
또는 history.replaceState()
를 호출한다고, popstate이벤트가 트리거 되지는 않는다. 뒤로가기, 앞으로 가기 버튼 또는 history.back(), forward()
과 같은 자바스크립트를 통한 호출에 의해서만 트리거가 발생한다.
또한 새로고침을 눌렀을 경우에는 없는 페이지라고 뜨기 때문에 이 부분은 서버사이드 렌더링으로 해결해야한다.
참고:
링크해갑니다~버튼을 누르지 않고 해당 페이지로 접속했을때 url이 바뀌는 방법은 없을까요?