Introduction

pushstate

pushstae란?

HTML5 에서 새로 추가된 history객체의 method로 session history 에 주어진 타이틀로, 주어진 데이터를 쓰며 url이 주어진 경우 적용합니다.

사양참조 : http://www.w3.org/TR/html5/browsers.html#dom-history-pushstate

 

왜 pushstae를 사용하는가?

먼저 전통적인 웹 개발방식에 의해 만들어진 웹페이지를 생각해보겠습니다.

A 화면에서 B 화면으로 이동하기 위해 우리는 anchor tag나 form submit 등을 이용하여 페이지를 이동합니다.

또한 현재 화면의 데이터를 저장하려면 hidden tag 나, 세션, 쿠키등을 사용하여야 하고

일반적으로 사용자가 데이터에 대한 처리를 하고자 할 때 페이지를 호출하는 것 ( URL을 호출하는 것) 이외에 다른 방법은 없습니다.

그렇다면 url에 데이터를 저장하려면 어떻게 해야 할까요?

가장 간단한 방법은 queryString (질의문자열) 과 #를 사용하는 것입니다.

ex) http://www.slipp.net/wiki/pages/editpage.action?pageId=19530134&userid=gogo

 http://www.slipp.net/wiki/pages/writepage#pushstateinfo

관련 객체

   window.location   

   window.location.search

#를 쓰면 데이터를 편하게 저장할 수 있습니다. 

 

그런데 #를 사용했을 때의 문제는 #뒤의 내용을 변경하면 히스토리도 같이 변경됩니다.

따라서 뒤로가기버튼 클릭과 같은 상황에 대해서 일반적으로 대응할 수가 없습니다.

물론 타이머를 이용해서 주기적으로 #값을 체크해서 변경되면 해당페이지를 복원하는 방법도 있지만 예외처리에 대한 비용이 지나치게 많이듭니다.

그래서 HTML5에 추가된 history.pushstate, history.replaceState를 이용해서 보다 편리하게 history를 관리하게 되었고

이를 통해서 사용자가 의도하지 않은 행동 back 버튼등을 클릭하거나 다시 앞으로 가기 버튼을 눌렀을 때

(url해시 또는  이벤트를 가로채서 처리할 수도 있겠지만..)
pushstate를 사용하면 상태가 변경되었을 때 URL자체를 업데이트해서 url에 상태를 반영할 수 있습니다.

pushstate API

pushstate 지원 브라우저

url 참고 : http://caniuse.com/#search=pushstate

 

간단한 예제로 알아보는 차이점

말로만 설명을 하는 것보다는 간단한 예제를 통해서 기존방식과의 차이와 사용법을 익혀보겠습니다.

전통적인 html 방식의 화면 전환

<!DOCTYPE html>
<html lang="ko">
<head>
<title>Basic 0</title>
</head>
<body>
<ul>
<li><a href="basic_1.html">첫번째 페이지</a></li>
<li><a href="basic_2.html">두번째 페이지</a></li>
<li><a href="basic_3.html">세번째 페이지</a></li>
<li><a href="basic_4.html">네번째 페이지</a></li>
</ul>
<div>
페이지를 선택해주세요.
</div>
</body>
</html>

샘플 소스

실행결과

    

 

Single Page 어플리케이션 방식인 경우

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Single Page</title>
    <script type="text/javascript">
        function viewContents(idx) {
        
            event.preventDefault();
        
            var con = document.getElementById("contents");
        
            switch (idx) {
                case 1: 
                    document.title = 'Single Page - 1';
                    con.innerHTML = "첫번째 페이지";
                    break;
                case 2: 
                    document.title = 'Single Page - 2';
                    con.innerHTML = "두번째 페이지";
                    break;
                case 3: 
                    document.title = 'Single Page - 3';
                    con.innerHTML = "세번째 페이지";
                    break;
                case 4: 
                    document.title = 'Single Page - 4';
                    con.innerHTML = "네번째 페이지";
                    break;
                default:
                    break;
            }
        }
    </script>
</head>
<body>
    <ul>
        <li><a href="#" onClick="viewContents(1);">첫번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(2);">두번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(3);">세번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(4);">네번째 페이지</a></li>
    </ul>
    <div id="contents">
        페이지를 선택해주세요.
    </div>
</body>
</html>

샘플소스

실행결과

    

 

pushstate 를 이용하는 경우

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Pushstate</title>
    <script type="text/javascript">
    
        window.onpopstate = function(event) {
          //alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
            loadStateContent(event.state);
        };
    
        function viewContents(idx) {
        
            event.preventDefault();
        
            var con = document.getElementById("contents");
        
            switch (idx) {
                case 1: 
                    history.pushState({page: 1, name:'양수한'}, 'PushState - 1', '?page=first')
                    con.innerHTML = "첫번째 페이지";
                    break;
                case 2: 
                    history.pushState({page: 2, name:'박재성'}, 'PushState - 2', '?page=second')
                    con.innerHTML = "두번째 페이지";
                    break;
                case 3: 
                    history.pushState({page: 3, name:'장진달'}, 'PushState - 3', '?page=third')
                    con.innerHTML = "세번째 페이지";
                    break;
                case 4: 
                    history.pushState({page: 4, name:'양완수'}, 'PushState - 4', '?page=fourth')
                    con.innerHTML = "네번째 페이지";
                    break;
                default:
                    break;
            }
        }
        
        function loadStateContent(state) {
            var con = document.getElementById("contents");
            con.innerHTML = "복구된 " + state.page + "번째 페이지 " + "hello " + state.name;
        }
    </script>
</head>
<body>
    <ul>
        <li><a href="#" onClick="viewContents(1);">첫번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(2);">두번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(3);">세번째 페이지</a></li>
        <li><a href="#" onClick="viewContents(4);">네번째 페이지</a></li>
    </ul>
    <div id="contents">
        페이지를 선택해주세요.
    </div>
</body>
</html>






 

샘플소스

실행결과