웹개발/JavaScript

모달, 바텀시트 등의 UI가 띄워져 있을 때, 웹브라우저의 뒤로가기를 막고 닫기 처리하는 방법

donsohn 2024. 1. 20. 01:54

모달이나 바텀시트 컴포넌트는 사용자의 주의를 환기시키거나 또는 중요한 정보를 전달해야 할 때 매우 유용하게 사용됩니다.

그런데 사용자가 해당 창을 닫기 위해 웹 브라우저의 뒤로가기 동작을 수행하게 되면 이전 페이지로 되돌아가버리게 됩니다.

이는 결국 사용성을 해치는 것이 되는데요, 모달이 띄워져 있을 때 웹 브라우저 자체의 뒤로가기를 했을 때 이전 페이지로 이동되지 않고 열려 있는 모달창(또는 바텀시트나 팝업 등)을 닫으려면 아래와 같이 구현하면 됩니다.

본 포스팅에서는 모달을 예시로 설명하고 있으나 모달 뿐만이 아니라 어떤 컴포넌트라도 응용이 가능합니다.

모달 컴포넌트와 이를 열어주는 버튼은 이미 구현했다고 가정하겠습니다.

let isModalOpen = false;

// 모달 띄우기
function handleOpenModal() {
    isModalOpen = true;
    document.querySelector('.modal').classList.add('show');
    history.pushState({ isModalOpen: true }, '');
}

// 모달 닫기
function handleCloseModal() {
    isModalOpen = false;
    document.querySelector('.modal').classList.remove('show');
    history.replaceState({ isModalOpen: false }, '');
}

// 브라우저의 히스토리 변경이 일어날 시 실행될 코드
window.onpopstate = function (event) {
    if ( isModalOpen ) {
        // 모달이 띄워져 있으면 모달을 닫습니다.
        handleCloseModal();
    } else {
        // 모달이 띄워져 있지 않다면 이전 페이지로 이동합니다.
        history.go(-1);
    }
}

history.pushState

history.pushState() 메서드는 브라우저에 새로운 히스토리 엔트리를 생성합니다.

history.pushState(state, unused, url);

state

상태를 관리하는 객체로, pushState()에 의해 새로운 히스토리 엔트리가 추가되었을 때, popstate 이벤트가 발생합니다.

이 때 popstatestate 속성은 히스토리 엔트리 상태의 복사본을 담게 됩니다.

state 객체에는 직렬화가 가능한 모든 형태의 데이터를 지정할 수 있습니다.

unused

현재는 사용되지 않는 인자이며, 빈 값으로 지정하면 됩니다.

url

새로운 히스토리 엔트리의 URL입니다. 여기에는 절대경로와 상대경로 모두 지정해줄 수 있으며 상대경로일 경우, 현재 페이지의 동일한 origin을 가지고 있어야 합니다.

history.replaceState

history.replaceState() 메서드는 새로운 히스토리 엔트리를 추가하지 않고, 현재의 엔트리를 새로운 엔트리로 덮어씌웁니다.

history.replaceState(state, unused, url);

인자는 history.pushState() 메서드와 마찬가지로 동일한 3가지를 제공하며, 역할 또한 비슷합니다.

window.onpopstate

window 객체의 onpopstate 이벤트는 웹 브라우저의 뒤로가기/앞으로가기 동작으로 인해 현재 히스토리 엔트리에 변화가 생길 때 발생하게 됩니다.

예를 들어, 사용자가 뒤로가기 버튼을 누르게 되면 popstate 이벤트가 발생하고 event.state를 통해서 해당 상태 객체에 접근할 수 있습니다.

window.onpopstate = function (event) {
    // event.state에는 pushState 또는 replaceState에서 전달한 상태 객체가 들어있습니다.
    const state = event.state;

    // 여기서 상태에 따른 동작을 수행할 수 있습니다.
};

이와 같이 window.onpopstate, history.pushState, history.replaceState를 이용해서 매우 간단하게 상태 값에 따른 뒤로가기 제어가 가능합니다.