모달 레이어 팝업 등에서 URL을 변경해 뒤로 가기 버튼을 작동하게 하기 – pushState, popstate 활용 규칙 메모

,
black and gray compass on top of map
Photo by Alexander Andrews on Unsplash

미리보기를 띄우면 URL에 ?preview가 붙으면서 미리보기가 뜨고, 미리보기를 닫으면 URL에 있는 ?preview가 사라지면서 닫히는 식의 기능을 만들 때 참고하려고 정리한 메모입니다. pushState()popstate를 사용합니다.

이렇게 URL을 달리하면 prev, next 버튼에 따라서 미리보기가 닫히고 열립니다.

그리고 해당 URL로 직접 접근했을 때도 미리 보기를 열거나 닫을 수 있습니다.

메모

history.pushState()는 URL을 바꾸고 History의 단계는 추가하지만 window에 popstate 이벤트는 발생시키지 않습니다.

popstate 이벤트는 뒤로 가기 버튼이나 앞으로 가기 버튼을 클릭하는 경우, 혹은 JS에서 history.back()이나 history.forward()를 호출한 경우에만 발생합니다.

따라서 URL에 따른 페이지 요소의 상태 변화는 다음과 같이 작성해야 합니다.

  1. open, close 메서드를 작성(또는 start, end 메서드).
  2. 클릭 이벤트에서 history.pushState() 실행하고 open, close 메서드(또는 start, end 메서드) 실행.
  3. toggleByUrl 작성. URL에 따라 open, close 메서드(또는 start, end 메서드) 실행하는 메서드.
  4. popstate 이벤트 핸들러로 toggleByUrl 메서드 바인딩.
  5. URL로 직접 들어왔을 때 toggleByUrl 메서드 바인딩.

예시

아래는 지금 제 블로그에서 사용하는 print.js 파일과 관련 CSS 내용입니다.

이 글의 제목 아래쪽 프린트 버튼을 눌러 보시면 어떤 효과인지 확인하실 수 있습니다.

if (document.querySelector('.js-start-print-mode')) {

    const start = () => {
        window.scrollTo(0, 0);
        document.body.classList.add('print');
    }

    const end = () => {
        document.body.classList.remove('print');
    }

    const addSearchParamOnUrl = () => {
        history.pushState({isPrintMode: true}, '', '?print-mode');
    }
    const removeSearchParamOnUrl = () => {
        let url = new URL(location);
        url.searchParams.delete('print-mode');
        history.pushState({isPrintMode: false}, '', url);
    }

    const toggleByUrl = () => {
        let url = new URL(location);

        if (url.searchParams.has('print-mode')) {
            start();
        }

        if (!url.searchParams.has('print-mode')) {
            end();
        }
    }

    document.querySelector('.js-start-print-mode').addEventListener('click', e => {
        addSearchParamOnUrl();
        start();
    });

    document.querySelector('.js-end-print-mode').addEventListener('click', e => {
        removeSearchParamOnUrl();
        end();
    });

    window.addEventListener('popstate', toggleByUrl);

    toggleByUrl();
}
.no-print-but-show-on-print-mode-display {
    display: none
}

.print .no-print-but-show-on-print-mode-display {
    display: block;
    text-align: center
}

@media print {
    .print .no-print-but-show-on-print-mode-display {
        display: none
    }

    .print h1, .print h2, .print h3, .print h4, .print h5, .print h6 {
        -moz-column-break-after: avoid;
        break-after: avoid
    }
}

👇 카테고리 글 목록

,

대표글

댓글 남기기