본문 바로가기

[IT/Programming]/HTML related

Change browser URL (window.location) without reloading or redirecting a page

반응형
m.logPrint() is working!

<eq> and <eqq> tags are rendered to MathJax format, being enclosed by \ ( \ ) and \ [ \ ].

docuK-1 scripts started!
If this log is not closed automatically, there must be an error somewhere in your document or scripts.

Table of Contents is filled out.

Auto numberings of sections (div.sec>h2, div.subsec>h3, div.subsubsec>h4), <eqq> tags, and <figure> tags are done.

<cite> and <refer> tags are rendered to show bubble reference.

<codeprint> tags are printed to corresponding <pre> tags, only when the tags exist in the document.


Current styles (dark/bright mode, font-family, font-size, line-height) are shown.

disqus.js with id="disqus-js" is loaded.

kakao.js with id="kakao-jssdk" is loaded.

New ShortKeys (T: Table of Contents, F: Forward Section, D: Previous Section, L: To 전체목록/[Lists]) are set.

m.delayPad=0;
m.wait=1024;
wait 867ms.
▼ Hide
Toggle a mess
Go (FS)
TofC
DocuK Log
Backward
Forward
RRA
Lists
CmtZ
CmtX
Handle CmtZ
Log in
out focus
Mode: Bright; Font: Noto Sans KR; font-size: 18.0px (10.0); line-height: 1.6;
width: 1280, height: 720, version: 2.12.18
Canonical URI: https://kipid.tistory.com/entry/Change-browser-URL-without-reloading-a-page
dg:plink (Document Global Permanent Link): https://kipid.tistory.com/136
document.referrer: Empty
This document is rendered by docuK (See also SEE (Super Easy Edit) of docuK and pure SEE).

Change browser URL or URI (window.location, Unique Resource Identifier) without reloading or redirecting a page

페이지를 일부만 바꾸고 싶을때, 혹은 JavaScript 변수들/데이터들을 유지하고 싶을때, 주로 AJAX request 를 이용한다. 그런데 사용자에게 일부가 바뀐 이 페이지의 주소는 이것이다라고 알려주고 다른 사람들과 공유하기 편하게 하려면, 바뀐 페이지에 바로 접속할 수 있는 주소로 URL (window.location) 이 바뀌어주는 것이 좋아보인다. 물론 이 주소로 접속을 하면 서버에서는 그 바뀐 페이지를 다시 보여주도록 디자인되어야 할테고.
인스타그램, 페이스북, GitHub 등의 사이트들에서 몇가지 (특히 navigation menu) 를 이렇게 구현해 놓은 것 같다. 전체 주소뒤에 hash(#) 를 붙여서 하는게 아니라, URL 의 domain part 를 제외한 path 부분을 page reload 없이 바꾸는 형태로 동작한다.
물론 내부적으로는 AJAX 로 데이터를 주고 받을듯 하지만 페이지가 완전히 reload/redirect 되는 것은 아니고 일부분만 바뀐다. 그리고 이렇게 바뀌어진 URL 로 새 창에서 접속해도 비슷한 화면이 띄워진다. (구현 방법에 따라 완전히 똑같은 화면은 안뜰수도 있음.)

T1.Browser Objects - window.location

▼ Show/Hide
기본적으로 JavaScript Browser Objects 에 window.location 이란게 있음 .

T1.1.All properties of window.location

On the left side of codes is there a hiden button to toggle/switch scrollability ({max-height:some} or {max-height:none}).
<script>
(function () {
	let currentPath=window.location.pathname+window.location.search+window.location.hash;
	// State 만 update
	window.history.pushState({JSON:"new state"}, null);

	// 전체 path 바꾸기
	window.history.pushState(null, null, "/path/will/be/changed/null");
	window.history.pushState({some:"data1"}, "state1", "/path/will/be/changed/state1?a=b&c=d#state1");
	window.history.pushState({some:"data2"}, "state2", "/path/will/be/changed/state2");
	window.history.pushState({some:"data3"}, "state3", "/path/will/be/changed/state3?a=c&b=d#state3");
	window.history.pushState({some:"data4"}, "state4", "/path/will/be/changed/state4");
	window.history.pushState({some:"data5"}, "state5", "/path/will/be/changed/state5");
	window.history.pushState({some:"data6"}, "state6", "/path/will/be/changed/state6");
	window.history.pushState({some:"data7"}, "state7", "/path/will/be/changed/state7?a=b&c=d#state7");
	window.history.pushState({currentPath:currentPath}, "state0", currentPath);

	let str="for (let p in window.location) {\n"
		+"\tstr+=p+\" : \"+window.location[p]+\"\\n\";\n"
		+"}\n\n"
		+"// All properties of window.location\n";
	for (let p in window.location) {
		str+=p+" : "+window.location[p]+"\n";
	}
	$("#location-result").html(str);
})();
</script>
On the left side of codes is there a hiden button to toggle/switch scrollability ({max-height:some} or {max-height:none}).
for (let p in window.location) {
	str+=p+" : "+window.location[p]+"\n";
}

// All properties of window.location
ancestorOrigins : [object DOMStringList]
href : https://kipid.tistory.com/entry/Change-browser-URL-without-reloading-a-page?category=751809
origin : https://kipid.tistory.com
protocol : https:
host : kipid.tistory.com
hostname : kipid.tistory.com
port : 
pathname : /entry/Change-browser-URL-without-reloading-a-page
search : ?category=751809
hash : 
assign : function assign() { [native code] }
reload : function reload() { [native code] }
replace : function replace() { [native code] }
toString : function toString() { [native code] }

T1.2.URL 의 기본구조

전체 URL 은 위에서 보이듯 href 로 뽑아낼 수 있음. 이 URL 은
// The entire URL
[href]=[protocol]//[hostname]:[port][/pathname][?search][#hash]
	=[protocol]//[host][/pathname][?search][#hash]
	=[origin][/pathname][?search][#hash]

// Host
[host]=[hostname]:[port]

// Origin
[origin]=[protocol]//[hostname]:[port]
	=[protocol]//[host]
형태로 구성되어 있음.

T1.3.Change URL

이 window.location 을 이용해서 URL 을 다음과 같은 명령어들로 바꿀 수 있음. 그런데 이걸 이용하면 바뀐 URL 에 해당하는 페이지를 아예 새로 load 함 (hash 만 제외).
On the left side of codes is there a hiden button to toggle/switch scrollability ({max-height:some} or {max-height:none}).
// 새로고침
window.location.reload();

// 아예 새로운 URL 로 이동.
window.location="http://www.daum.net";
window.location.href="http://www.daum.net";
window.location.assign("http://www.daum.net");
window.location.replace("http://www.daum.net");
	// replace 는 뒤로가기 활성화 안됨.

// path 부분만 바꿔서 이동.
window.location="/new/path";
window.location.href="/new/path";
window.location.pathname="new/path";
window.location.pathname="/new/path";

// path 의 마지막 부분만 바꿔서 이동.
window.location.href="the-last-path/is/changed";
	// window.location.pathname= 로는 처음에 "/" 가 없어도 전체 path 가 바뀜.

// host 부분만 바꿀수도 있는듯? 쓸일은 거의 없겠지만...
window.location.host="tistory.com";
window.location.hostname="tistory.com";

// query 부분 (?이후-부분) 바꾸기.
window.location="?a=b&c=d";
	// 이 경우 hash 는 지워짐.
window.location.search="a=b&c=d";
	// The querystring part is the part of the URL after the question mark (?). This is often used for parameter passing.

// hash 부분 (#이후-부분) 바꾸기. 이건 page reload 없음.
window.location="#some-hash";
window.location.hash="some-hash";
	// When used to set the anchor part, do not include the hash sign (#).
▲ Hide

T2.Change browser URL without redirecting a page

▼ Show/Hide
window.history 를 이용하면, page reload 없이도 URL path 부분을 바꿀 수 있음. 참고 :
[03]
Ref. [03] StackOverflow - Modify the URL without reloading the page, 2009-05-05, asked by Jarvis, answered by David Murdoch
[05]
. (그런데 history 안의 URL list 는 못 뽑아내는듯? 보안문제 때문인가?)
for (let p in window.history) {
	str+=p+" : "+window.history[p]+"\n";
}

// All properties of window.history
length : 22
scrollRestoration : auto
state : [object Object]
back : function back() { [native code] }
forward : function forward() { [native code] }
go : function go() { [native code] }
pushState : function pushState() { [native code] }
replaceState : function replaceState() { [native code] }

T2.1.Traveling through history : window.history - .back(), .forward(), .go(Number n)

window.history 는 이름에서도 알 수 있듯이 기본적으로 "뒤로 가기", "앞으로 가기" 등에 쓰였던 JavaScript Object 임. 다음과 같은 javascript 명령어들로 "뒤로 가기", "앞으로 가기" 등이 실행 가능함.
// 뒤로 가기
window.history.back();
window.history.go(-1);

// 앞으로 가기
window.history.forward();
window.history.go(1);

// 뒤로 두번 가기
window.history.go(-2);

// 앞으로 두번 가기
window.history.go(2);

T2.2.window.history .pushState()

아래와 같은 명령어를 console 창에 치면 page reload 없이 URL 의 path 부분이 바뀌는 것을 알 수 있음. 또한 뒤로가기도 활성화 됨. (크롬에서만 그런건지 모르겠는데, 스크롤 위치가 바뀔 경우 스크롤 위치도 기억했다가 되돌리는듯?)
window.history.pushState({JSON:"data"}, "title" [, "/new-path?search#hash"]);
	// pushState() takes three parameters: a state object, a title (which is currently ignored), and (optionally) a URL.
	// 첫번째 parameter {JSON:"data"} 는 window.history.state 에 저장되어서 나중에 뽑아낼 수 있음.
	// 두번째 parameter 는 아직 쓰이는데가 없는듯? 왜 만든겨?
	// 세번째 parameter 가 URL path 를 바꿈. "search, hash" 값을 포함하는 full path 가 들어감.

// State 만 update
window.history.pushState({JSON:"new state"}, null);

// 전체 path 바꾸기
window.history.pushState(null, null, "/path/will/be/changed/null");
window.history.pushState({some:"data1"}, "state1", "/path/will/be/changed/state1?a=b&c=d#state1");
window.history.pushState({some:"data2"}, "state2", "/path/will/be/changed/state2");
window.history.pushState({some:"data3"}, "state3", "/path/will/be/changed/state3?a=c&b=d#state3");
window.history.pushState({some:"data4"}, "state4", "/path/will/be/changed/state4");
window.history.pushState({some:"data5"}, "state5", "/path/will/be/changed/state5");
window.history.pushState({some:"data6"}, "state6", "/path/will/be/changed/state6");
window.history.pushState({some:"data7"}, "state7", "/path/will/be/changed/state7?a=b&c=d#state7");

// 마지막 path 만 바꾸기
window.history.pushState(null, null, "the-last-path/will/be/changed");

T2.3.window.history .replaceState()

다음과 같은 명령어로는 "뒤로 가기"를 활성화 안시키고 URL path 를 바꿀수 있음.
window.history.replaceState({JSON:"data"}, "title", "/new-path");

// 전체 path 바꾸기
window.history.replaceState({}, "", "/path/will/be/changed");

// 마지막 path 만 바꾸기
window.history.replaceState({}, "", "the-last-path/will/be/changed");
▲ Hide

T3.window .onpopstate

▼ Show/Hide
Whenever the user navigates to the new state, a popstate event is fired, and the state property of the event contains a copy of the history entry's state object.
아래와 같이 function 을 window.onpopstate 에 asign 해 놓으면, "앞으로 가기"/"뒤로 가기" 등으로 state 가 바뀔때마다 해당 function 이 불려짐. 따라서 페이지가 처음 불려질때나 reload 될때는 call 되지 않음. window.history.pushState() 가 실행될때도 불려지지 않음. (그런데 window.onpopstate 이용해서 구현한 사이트들은 거의 없는듯?)
// 기본적으로 window.onpopstate 는 null 임.
window.onpopstate=function(e) {
	console.log(e.state);
};
아래는 개인적으로 넣어놓은 onpopstate 가 불려질때 event.state, event 의 all properties 출력 결과. State 들 몇개를 넣어놨으니 뒤로가기를 눌러보시길. (setTimout 은 state 가 바뀐 뒤에도 동작을 함 =ㅇ=;;; 스크롤이 제멋대로길래 $(window).scrollTop() 를 이용했는데, 브라우저 기본동작이 내껄 덮어씌우길래 setTimeout 걸어놨음. 아마도 onpopstate function 이 불려지고 난 후, 이전 스크롤 위치를 찾아가는 scroll function 이 불려지는듯?)
On the left side of codes is there a hiden button to toggle/switch scrollability ({max-height:some} or {max-height:none}).
▲ Hide
반응형
Get page views