내 AJAX 애플리케이션에서 뒤로 버튼에 대한 호출 가로 채기
AJAX 앱이 있습니다. 사용자가 버튼을 클릭하면 페이지 표시가 변경됩니다. 그들은 원래 상태로 가기를 기대하면서 뒤로 버튼을 클릭하지만 대신 브라우저의 이전 페이지로 이동합니다.
뒤로 버튼 이벤트를 차단하고 다시 할당하려면 어떻게해야합니까? 나는 RSH와 같은 라이브러리를 살펴 봤는데 (작업 할 수 없었습니다 ...), 해시 태그를 사용하는 것이 어떻게 든 도움이된다고 들었지만 이해할 수 없습니다.
아, 뒤로 버튼. "뒤로"가 다음과 같이 간단히 취소 할 수있는 JavaScript 이벤트를 실행한다고 상상할 수 있습니다.
document.onHistoryGo = function() { return false; }
아니. 그러한 이벤트는 없습니다.
실제로 웹 앱 이있는 경우 (아약시 기능이있는 웹 사이트가 아닌) 뒤로 버튼을 사용하는 것이 합리적입니다 (언급했듯이 URL에 조각이 있음). Gmail이이를 수행합니다. 웹 앱이 한 페이지에 모두 포함되어있는 경우에 대해 이야기하고 있습니다.
이 기술은 간단합니다. 사용자가 무언가를 수정하는 작업을 수행 할 때마다 이미있는 동일한 URL로 리디렉션하지만 다른 해시 조각을 사용합니다. 예
window.location.hash = "#deleted_something";
...
window.location.hash = "#did_something_else";
웹 앱의 전체 상태가 해시 가능한 경우 해시를 사용하기 좋은 곳입니다. 이메일 목록이 있다고 가정하면 모든 ID와 읽음 / 읽지 않음 상태를 연결하고 MD5 해시를 조각 식별자로 사용하여 사용할 수 있습니다.
이런 종류의 리디렉션 (해시 만 해당)은 서버에서 아무것도 가져 오지 않지만 브라우저의 기록 목록에 슬롯을 삽입합니다. 따라서 위의 예에서 사용자가 "뒤로"를 누르면 이제 주소 표시 줄에 #deleted_something 이 표시됩니다. 그들은 다시 맞았고 그들은 여전히 당신의 페이지에 있지만 해시는 없습니다. 그런 다음 다시 돌아와 실제로 어디에서 왔든 다시 돌아갑니다.
이제 어려운 부분은 JavaScript가 사용자가 반격 할 때 감지하도록하는 것입니다 (상태를 되돌릴 수 있음). 창 위치를보고 언제 변경되는지 확인하는 것뿐입니다. 투표와 함께. (나도 알아요, 투표합니다. 글쎄요, 지금은 브라우저 간 더 나은 것은 없습니다). 그래도 앞뒤로 갔는지 알 수 없으므로 해시 식별자로 창의력을 발휘해야합니다. (아마도 시퀀스 번호와 연결된 해시 ...)
이것이 코드의 요점입니다. (이것은 또한 jQuery History 플러그인이 작동하는 방식입니다.)
var hash = window.location.hash;
setInterval(function(){
if (window.location.hash != hash) {
hash = window.location.hash;
alert("User went back or forward to application state represented by " + hash);
}
}, 100);
오래되었지만 인기있는 질문에 대한 최신 답변을 제공하려면 :
HTML5는 히스토리 항목을 각각 추가하고 수정할 수 있는
history.pushState()
및history.replaceState()
메서드를 도입 했습니다. 이러한 방법은window.onpopstate
이벤트 와 함께 작동합니다 .를 사용 하면 상태를 변경 한 후 생성 된 객체
history.pushState()
에 대해 HTTP 헤더에서 사용되는 리퍼러가XMLHttpRequest
변경됩니다. 리퍼러는 객체this
생성시 창이있는 문서의 URL이 됩니다XMLHttpRequest
.
출처 : Mozilla 개발자 네트워크에서 브라우저 히스토리 조작 .
jQuery를 사용하여 간단한 솔루션을 만들었습니다.
$(window).on('hashchange', function() {
top.location = '#main';
// Eventually alert the user describing what happened
});
지금까지는 Google 크롬에서만 테스트되었습니다.
이것은 또한 고도의 AJAX 기반 인 내 웹 앱의 문제를 해결했습니다.
그것은 아마도 약간 hack'ish-그러나 나는 그것을 우아한 해킹이라고 부를 것입니다 ;-) 뒤로 탐색하려고 할 때마다 기술적으로는 URI에 해시 부분이 나타납니다.이 부분은 기술적으로 뒤로 탐색하려고 시도합니다.
브라우저 버튼과 마우스 버튼을 모두 차단합니다. 그리고 초당 여러 번 클릭하여 뒤로 무차별 대입 할 수 없습니다. 이는 setTimeout 또는 setInterval 기반 솔루션에서 발생하는 문제입니다.
나는 darkporter의 대답에 주어진 설명을 정말로 고맙게 생각한다. 그러나 나는 그것이 " hashchange "이벤트를 사용함으로써 개선 될 수 있다고 생각한다 . darkporter가 설명했듯이 모든 버튼이 window.location.hash 값을 변경하는지 확인하고 싶습니다.
- 한 가지 방법은
<button>
요소 를 사용한 다음window.location.hash = "#!somehashstring";
. - 이를 수행하는 또 다른 방법은 버튼에 대한 링크를 사용하는 것
<a href="#!somehashstring">Button 1</a>
입니다. 이러한 링크를 클릭하면 해시가 자동으로 업데이트됩니다.
해시 기호 뒤에 느낌표가있는 이유는 Google의 "hashbang"패러다임을 충족하기위한 것입니다 ( 자세히 알아보기 ). 검색 엔진에서 색인을 생성하려는 경우 유용합니다. 해시 문자열은 일반적으로 웹 앱에 적합한 이름 / 값 쌍 #!color=blue&shape=triangle
또는 목록과 같습니다 #!/blue/triangle
.
그런 다음 해시 값이 변경 될 때마다 ( 뒤로 버튼을 눌렀을 때를 포함하여) 실행될이 코드 비트 만 추가하면됩니다 . 폴링 루프가 필요하지 않은 것 같습니다.
window.addEventListener("hashchange", function(){
console.log("Hash changed to", window.location.hash);
// .... Do your thing here...
});
Chrome 36 외에는 테스트하지 않았지만 caniuse.com에 따르면 IE8 +, FF21 +, Chrome21 + 및 Opera Mini를 제외한 대부분의 다른 브라우저에서 사용할 수 있습니다.
아래의 JQuery 코드와 같이 브라우저의 BACK 버튼을 비활성화하는 것은 매우 쉽습니다 .
// History API
if( window.history && window.history.pushState ){
history.pushState( "nohb", null, "" );
$(window).on( "popstate", function(event){
if( !event.originalEvent.state ){
history.pushState( "nohb", null, "" );
return;
}
});
}
여기 dotnsf 및 여기 thecssninja 에서 작동하고 더 많은 예제를 볼 수 있습니다.
감사 !
개인 정보 보호 문제로 인해 뒤로 버튼을 비활성화하거나 사용자 기록을 검토하는 것은 불가능하지만 페이지를 변경하지 않고이 기록에 새 항목을 만들 수 있습니다. AJAX 애플리케이션이 상태를 변경할 때마다 top.location
새 URI 조각으로 업데이트 합니다.
top.location = "#new-application-state";
그러면 브라우저의 히스토리 스택에 새 항목이 생성됩니다. 많은 AJAX 라이브러리가 이미 Really Simple History 와 같은 모든 지루한 세부 사항을 처리합니다 .
제 상황에서는 뒤로 버튼이 사용자를 마지막 페이지로 보내는 것을 막고 대신 다른 조치를 취하고 싶었습니다. hashchange
이벤트를 사용하여 나는 나를 위해 일한 솔루션을 찾았습니다. 이 스크립트는 사용중인 페이지가 제 경우와 같이 이미 해시를 사용하지 않는다고 가정합니다.
var hashChangedCount = -2;
$(window).on("hashchange", function () {
hashChangedCount++;
if (top.location.hash == "#main" && hashChangedCount > 0) {
console.log("Ah ah ah! You didn't say the magic word!");
}
top.location.hash = '#main';
});
top.location.hash = "#";
다른 답변 중 일부에 대해 가지고 있던 문제는 hashchange
이벤트가 발생하지 않는다는 것입니다. 상황에 따라 이것도 효과가있을 수 있습니다.
나는 일반 역사의 행동을 무시하고 뚜렷한 만드는 방법 밖으로 일을 back
하고 forward
HTML5의 역사 API를 (이것은 IE 9에서 작동하지 않습니다)를 사용하여, 버튼 이벤트를. 이것은 매우 엉망이지만 뒤로 및 앞으로 버튼 이벤트를 가로 채서 원하는대로 처리하려는 경우 효과적입니다. 이는 원격 데스크톱 창을 표시하고 원격 시스템에서 뒤로 및 앞으로 버튼 클릭을 재현해야하는 경우와 같은 여러 시나리오에서 유용 할 수 있습니다.
다음은 뒤로 및 앞으로 버튼 동작을 재정의합니다.
var myHistoryOverride = new HistoryButtonOverride(function()
{
console.log("Back Button Pressed");
return true;
},
function()
{
console.log("Forward Button Pressed");
return true;
});
이러한 콜백 함수 중 하나에서 false를 반환하면 브라우저가 정상적인 뒤로 / 앞으로 작업을 진행하고 페이지를 떠날 수 있습니다.
다음은 필요한 전체 스크립트입니다.
function HistoryButtonOverride(BackButtonPressed, ForwardButtonPressed)
{
var Reset = function ()
{
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
}
var BuildURLWithHash = function ()
{
// The URLs of our 3 history states must have hash strings in them so that back and forward events never cause a page reload.
return location.origin + location.pathname + location.search + (location.hash && location.hash.length > 1 ? location.hash : "#");
}
if (history.state == null)
{
// This is the first page load. Inject new history states to help identify back/forward button presses.
var initialHistoryLength = history.length;
history.replaceState({ customHistoryStage: 1, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 2, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.pushState({ customHistoryStage: 3, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash());
history.back();
}
else if (history.state.customHistoryStage == 1)
history.forward();
else if (history.state.customHistoryStage == 3)
history.back();
$(window).bind("popstate", function ()
{
// Called when history navigation occurs.
if (history.state == null)
return;
if (history.state.customHistoryStage == 1)
{
if (typeof BackButtonPressed == "function" && BackButtonPressed())
{
Reset();
return;
}
if (history.state.initialHistoryLength > 1)
history.back(); // There is back-history to go to.
else
history.forward(); // No back-history to go to, so undo the back operation.
}
else if (history.state.customHistoryStage == 3)
{
if (typeof ForwardButtonPressed == "function" && ForwardButtonPressed())
{
Reset();
return;
}
if (history.length > history.state.initialHistoryLength + 2)
history.forward(); // There is forward-history to go to.
else
history.back(); // No forward-history to go to, so undo the forward operation.
}
});
};
This works by a simple concept. When our page loads, we create 3 distinct history states (numbered 1, 2, and 3) and navigate the browser to state number 2. Because state 2 is in the middle, the next history navigation event will put us in either state 1 or 3, and from this we can determine which direction the user pressed. And just like that, we've intercepted a back or forward button event. We then handle it however we want and return to state number 2 so we can capture the next history navigation event.
Obviously, you would need to refrain from using history.replaceState and history.pushState methods while using the HistoryButtonOverride script, or else you'd break it.
The back button in the browsers normally tries to go back to the previous address. there is no native device back button pressed event in browser javascript, but you can hack it with playing with location and hash to change your app state.
imagine the simple app with two views:
- default view with a fetch button
- result view
to implement it, follow this example code:
function goToView (viewName) {
// before you want to change the view, you have to change window.location.hash.
// it allows you to go back to the previous view with the back button.
// so use this function to change your view instead of directly do the job.
// page parameter is your key to understand what view must be load after this.
window.location.hash = page
}
function loadView (viewName) {
// change dom here based on viewName, for example:
switch (viewName) {
case 'index':
document.getElementById('result').style.display = 'none'
document.getElementById('index').style.display = 'block'
break
case 'result':
document.getElementById('index').style.display = 'none'
document.getElementById('result').style.display = 'block'
break
default:
document.write('404')
}
}
window.addEventListener('hashchange', (event) => {
// oh, the hash is changed! it means we should do our job.
const viewName = window.location.hash.replace('#', '') || 'index'
// load that view
loadView(viewName)
})
// load requested view at start.
if (!window.location.hash) {
// go to default view if there is no request.
goToView('index')
} else {
// load requested view.
loadView(window.location.hash.replace('#', ''))
}
I do something like this. I keep an array with previous app states.
Initiated as:
var backstack = [];
Then I listen for changes in the location hash, and when it changes I do this:
if (backstack.length > 1 && backstack[backstack.length - 2] == newHash) {
// Back button was probably pressed
backstack.pop();
} else
backstack.push(newHash);
This way I have a somewhat simple way of keeping track of user history. Now if I want to implement a back button in the app (not the browser-botton), I just make it do:
window.location.hash = backstack.pop();
'Nice programing' 카테고리의 다른 글
코드에서 여백 속성 설정 (0) | 2020.10.25 |
---|---|
“NoClassDefFoundError : 클래스를 초기화 할 수 없습니다.”오류 (0) | 2020.10.25 |
개체 목록에서 고유 한 필드 값을 반환하는 linq 쿼리 (0) | 2020.10.25 |
알려진 글꼴 크기 및 문자에 대한 WPF TextBlock 너비를 계산하는 방법은 무엇입니까? (0) | 2020.10.25 |
정적 라이브러리가 64 비트 용으로 빌드되었는지 확인하는 방법은 무엇입니까? (0) | 2020.10.25 |