본문 바로가기
Background
개발/JS

history를 사용해 앱처럼 뒤로가기

by BellRiver_Lee 2024. 10. 10.

최근 업무 중에 재밌는 요청이 있었습니다.

햄버거 메뉴나 검색 모달을 뒤로 가기 했을 때 모달 컨텐츠만 닫히고 페이지가 뒤로 가지 않았으면 좋겠다는 것이었습니다.
여차저차 성공해서 뒤로가기 했을 때 페이지가 뒤로 가는 것이 아닌 모달 컨텐츠만 닫히도록 하였습니다.

아래 코드의 진가는 모바일 제스쳐, 마우스 좌측의 뒤로 가기 버튼에 있습니다.
모바일에서 제스쳐 뒤로 가기나 마우스로 뒤로 가기를 해도 페이지 이동이 아닌 모달 컨텐츠만 닫히는 것입니다!
좀 더 앱 환경에 가까워진 것이죠.

이 좋은 걸 저 혼자만 알 수 없어서 코드를 다듬어 왔습니다.
아래 코드를 VS Code에서 라이브 서버로 보시면 한 눈에 이해하실 수 있습니다.

See the Pen Untitled by 이종원 (@orugpbqu-the-solid) on CodePen.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>앱처럼 컨텐츠 뒤로가기로 닫기</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
body{background: #000;}
.modal_content{display: none; width: 100px;height: 100px;background: #333;position: absolute;left: 100px;}
body.view_modal_content .modal_content{display: inline-block;}

</style>
</head>
<body>

    <button class="call_modal">call modal</button>
    <div class="modal_content"></div>

<script>
// 페이지 진입 시 .view_modal_content가 있을 경우 제거하기
// 페이지 막 들어갔는데 모달 컨텐츠가 열리는 것을 방지.
$(document).ready(function () {
    $("body").removeClass("view_modal_content");

    const currentUrl = window.location.href;
    const url = new URL(currentUrl);

    // URL에서 view_modal_content 파라미터 제거
    if (url.searchParams.has('view_modal_content')) {
        url.searchParams.delete('view_modal_content');
        window.history.replaceState(null, null, url.toString());
    }
});

// 모달 컨텐츠 보이기
$(document).on("click", ".call_modal", function () {
    $("body").toggleClass("view_modal_content");

    const currentUrl = window.location.href;
    const url = new URL(currentUrl);

    if ($("body").hasClass("view_modal_content")) {
        // .view_modal_content 클래스가 추가되었을 때 URL에 view_modal_content=true 추가
        if (!url.searchParams.has('view_modal_content')) {
            url.searchParams.set('view_modal_content', 'true');
            window.history.pushState(null, null, url.toString());
        }
    } else {
        // .view_modal_content 클래스가 제거되었을 때 URL에서 view_modal_content=true 제거
        url.searchParams.delete('view_modal_content');
        window.history.replaceState(null, null, url.toString());
    }
})

// popstate 이벤트를 통해 URL이 변경될 때 .view_modal_content 클래스 처리
window.addEventListener("popstate", function () {
    const currentUrl = window.location.href;
    const url = new URL(currentUrl);

    // URL에 view_modal_content 파라미터가 없으면 .view_modal_content 클래스 제거
    if (!url.searchParams.has('view_modal_content')) {
        $("body").removeClass("view_modal_content");
    } else {
        // URL에 view_modal_content 파라미터가 있으면 .view_modal_content 클래스 추가
        $("body").addClass("view_modal_content");
    }
});
</script>
</body>
</html>
728x90
반응형