source

브라우저 뒤로 버튼 이벤트 검출 방법 - 크로스 브라우저

gigabyte 2022. 9. 13. 22:08
반응형

브라우저 뒤로 버튼 이벤트 검출 방법 - 크로스 브라우저

사용자가 브라우저의 뒤로 버튼을 눌렀는지 여부를 어떻게 확실하게 감지합니까?

하여 단일 웹 에서 인 하는 방법은 입니까?#URL★★★★★★★★★★★★★★★★★?

도대체 왜 브라우저의 백버튼은 자신의 이벤트를 기동하지 않는 것일까!?

(주의: Sharky의 피드백에 따라 백스페이스를 검출하기 위한 코드를 포함했습니다.)

SO에서 이러한 질문을 자주 보았고 최근에는 백버튼 기능을 직접 제어하는 문제에 직면했습니다.어플리케이션에 가장 적합한 솔루션(Hash Navigation 포함 단일 페이지)을 며칠 동안 검색한 결과, 뒤로 버튼을 감지하기 위한 심플하고 크로스 브라우저가 필요 없는 시스템이 개발되었습니다.

대부분의 사용자는 다음을 사용할 것을 권장합니다.

window.onhashchange = function() {
 //blah blah blah
}

단, 이 함수는 사용자가 위치 해시를 변경하는 페이지 내 요소를 사용하는 경우에도 호출됩니다.사용자가 클릭했을 때 페이지가 앞뒤로 이동했을 때 최적의 사용자 환경이 아닙니다.

시스템의 대략적인 개요를 말씀드리면 사용자가 인터페이스를 이동할 때 어레이에 이전 해시를 채우고 있습니다.다음과 같습니다.

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

꽤 직설적이죠크로스 브라우저 지원 및 오래된 브라우저 지원을 보장하기 위해 이 작업을 수행합니다.새로운 해시를 함수에 전달하기만 하면 해시가 저장되고 해시가 변경됩니다(그 후 브라우저의 이력에 저장됨).

또한 내시킵니다.lasthash츠키다

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

따라서 사용자는 마지막 해시로 돌아가 어레이에서 마지막 해시를 삭제합니다(현재는 전달 버튼이 없습니다).

그러면 사용자가 내 페이지 뒤로 버튼이나 브라우저 버튼을 사용했는지 어떻게 알 수 있나요?

처음에 나는 보았다.window.onbeforeunload그러나 소용이 없습니다.이것은 사용자가 페이지를 변경하는 경우에만 호출됩니다.해시 탐색을 사용하는 단일 페이지 응용 프로그램에서는 이 작업이 수행되지 않습니다.

그래서 좀 더 파헤친 결과 플래그 변수를 설정하기 위한 권장 사항을 발견했습니다.이 경우 문제는 설정을 시도하지만 모든 것이 비동기이기 때문에 해시 변경 시 if 문장에 맞춰 항상 설정되지는 않는다는 것입니다. .onMouseDown항상 클릭으로 호출되는 것은 아니며, 클릭 클릭에 추가해도 충분히 빠르게 트리거되지 않습니다.

부터가 바로 그 시작했는데요.document , , , , 입니다.windowdocument.onmouseover를 사용하여 document.onmouseleave.

내에 읽기,프레임 ), 내 은 ""로 됩니다."true. 이 '부울'로 false.

하면 제가 수 요.window.onhashchange 삭제:

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

수표에 기입해 주세요.#undefined에 사용 경우 undefinedwindow.onbeforeunload

즉, 페이지 내 Back 버튼이나 어레이를 사용하여 이력을 저장할 필요가 없는 사용자에게는 다음과 같은 이점이 있습니다.

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

해시 네비게이션에 관한 백버튼 사용량과 페이지 내 요소를 검출하는 간단한 3가지 방법이 있습니다.

편집:

사용자가 백스페이스를 사용하여 백 이벤트를 트리거하지 않도록 하기 위해 다음 항목을 포함할 수도 있습니다(이 질문의 @thetoolman 덕분).

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});

이벤트 핸들러를 시험해 볼 수 있습니다.예를 들어 다음과 같습니다.

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

주의: 최상의 결과를 얻으려면 로직을 구현하는 특정 페이지에만 이 코드를 로드하여 다른 예기치 않은 문제를 방지하십시오.

popstate 이벤트는 현재 이력 엔트리가 변경될 때마다 실행됩니다(사용자는 새로운 상태로 이동합니다).때 "Back/Forward" 버튼을 클릭했을 때 합니다.history.back(),history.forward(),history.go()이치노

event.state이벤트 속성이 이력 스테이트오브젝트와 동일합니다.

jQuery 구문의 경우, 다음 순서로 감습니다(문서 준비 후 청취자까지 추가합니다).

(function($) {
  // Above code here.
})(jQuery);

참고 항목: 페이지 로드 시 window.onpopstate


Single-Page AppsHTML5 pushState 페이지의 예도 참조하십시오.

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

이는 Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ 등과 호환되어야 합니다.

저는 이 요건에 대해 오랫동안 고민해 왔고, 위의 몇 가지 솔루션을 사용하여 이 요건을 구현했습니다.그런데 우연히 관찰을 했는데 Chrome, Firefox 및 Safari 브라우저 + Android 및 iPhone에서 작동하는 것 같습니다.

페이지 로드 시:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

이게 도움이 되면 알려주세요.부족한 점이 있다면 기꺼이 이해하겠습니다.

을 javascript로 합니다.2브라우저의 뒤로 또는 앞으로 버튼을 클릭하여 브라우저가 실제로 캐시에서 콘텐츠를 가져오고 있음을 의미합니다.

if(performance.navigation.type == 2)
{
    //Do your code here
}
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

이 솔루션만이 유효합니다(한 페이지짜리 웹사이트가 아닙니다).Chrome, Firefox, Safari에서 작동합니다.

질문에 대한 정답은 이미 존재합니다.새로운 JavaScript API PerformanceNavigationTiming을 언급하고 싶습니다.이것은 폐지된 Performance.Navigation을 대체하는 것입니다.

사용자가 뒤로 또는 앞으로 버튼을 사용하여 페이지에 도착했을 경우 다음 코드는 콘솔 "back_forward"에 로그인합니다.프로젝트에서 사용하기 전에 호환성 표를 확인하십시오.

var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
    console.log(perfEntries[i].type);
}

이것은 확실히 동작합니다(뒤로 버튼 클릭 검출용).

$(window).on('popstate', function(event) {
 alert("pop");
});

마이 베리안트:

const inFromBack = performance && performance.getEntriesByType( 'navigation' ).map( nav => nav.type ).includes( 'back_forward' )

브라우저: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

모바일 제어: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>

다음을 참조하십시오.

history.pushState(null, null, location.href);
    window.onpopstate = function () {
        history.go(1);
    };

잘 작동한다...

이 스레드의 몇 가지 답변과 다른 답변을 사용하여 IE 및 Chrome/Edge에서 사용할 수 있었습니다.history.pushState는 IE11에서는 지원되지 않습니다.

if (history.pushState) {
    //Chrome and modern browsers
    history.pushState(null, document.title, location.href);
    window.addEventListener('popstate', function (event) {
        history.pushState(null, document.title, location.href);
    });
}
else {
    //IE
    history.forward();
}

API를 다시 정의해야 본격적인 컴포넌트를 구현할 수 있습니다(오브젝트 이력 메서드 변경). 방금 작성한 클래스를 공유하겠습니다.Chrome 및 Mozilla 지원에서만 테스트 완료 HTML5 및 ECMAScript5-6

class HistoryNavigation {
    static init()
    {
        if(HistoryNavigation.is_init===true){
            return;
        }
        HistoryNavigation.is_init=true;

        let history_stack=[];
        let n=0;
        let  current_state={timestamp:Date.now()+n};
        n++;
        let init_HNState;
        if(history.state!==null){
            current_state=history.state.HNState;
            history_stack=history.state.HNState.history_stack;
            init_HNState=history.state.HNState;
        } else {
            init_HNState={timestamp:current_state.timestamp,history_stack};
        }
        let listenerPushState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):{};
            let h_state={ timestamp:Date.now()+n};
            n++;
            let key = history_stack.indexOf(current_state.timestamp);
            key=key+1;
            history_stack.splice(key);
            history_stack.push(h_state.timestamp);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            current_state=h_state;
            return params;
        };
        let listenerReplaceState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):null;
            let h_state=Object.assign({},current_state);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            return params;
        };
        let desc=Object.getOwnPropertyDescriptors(History.prototype);
        delete desc.constructor;
        Object.defineProperties(History.prototype,{

            replaceState:Object.assign({},desc.replaceState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.replace',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerReplaceState(params);
                    desc.replaceState.value.call(this,params.state,params.title,params.url);
                }
            }),
            pushState:Object.assign({},desc.pushState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.push',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerPushState(params);
                    return desc.pushState.value.call(this, params.state, params.title, params.url);
                }
            })
        });
        HistoryNavigation.addEventListener('popstate',function(event){
            let HNState;
            if(event.state==null){
                HNState=init_HNState;
            } else {
                HNState=event.state.HNState;
            }
            let key_prev=history_stack.indexOf(current_state.timestamp);
            let key_state=history_stack.indexOf(HNState.timestamp);
            let delta=key_state-key_prev;
            let params={delta,event,state:Object.assign({},event.state)};
            delete params.state.HNState;
            HNState.history_stack=history_stack;
            if(event.state!==null){
                event.state.HNState=HNState;
            }
            current_state=HNState;
            HistoryNavigation.dispatchEvent('history.go',params);
        });

    }
    static addEventListener(...arg)
    {
        window.addEventListener(...arg);
    }
    static removeEventListener(...arg)
    {
        window.removeEventListener(...arg);
    }
    static dispatchEvent(event,params)
    {
        if(!(event instanceof Event)){
            event=new Event(event,{cancelable:true});
        }
        event.params=params;
        window.dispatchEvent(event);
    };
}
HistoryNavigation.init();

// exemple

HistoryNavigation.addEventListener('popstate',function(event){
    console.log('Will not start because they blocked the work');
});
HistoryNavigation.addEventListener('history.go',function(event){
    event.params.event.stopImmediatePropagation();// blocked popstate listeners
    console.log(event.params);
    // back or forward - see event.params.delta

});
HistoryNavigation.addEventListener('history.state.push',function(event){
    console.log(event);
});
HistoryNavigation.addEventListener('history.state.replace',function(event){
    console.log(event);
});
history.pushState({h:'hello'},'','');
history.pushState({h:'hello2'},'','');
history.pushState({h:'hello3'},'','');
history.back();

    ```

을 사용하다되어도 URL 에서 클릭이 document검출된 것은 브라우저의 되돌림(예 또는 전달)입니다.Ajax를 통해 콘텐츠를 로드하는 페이지에서 이 작업을 수행하기 위해 2초 후에 사용자 클릭이 리셋됩니다.

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);

document.mouseover는 IE 및 FireFox에서는 동작하지 않습니다.하지만 나는 이것을 시도했다:

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

이것은 Chrome과 IE에서는 동작하지만 Fire Fox에서는 동작하지 않습니다.FireFox를 바로 잡기 위해 아직도 노력하고 있어.브라우저의 뒤로/앞으로 버튼 클릭을 쉽게 검출할 수 있습니다.특히 JQuery뿐만 아니라 Angular에서도 마찬가지입니다.JS 또는 플레인 Javascript.

그 사건의 발단이 된 최초의 사건을 추적해서hashchange(슬라이프, 클릭, 휠 등) 이벤트가 단순한 페이지에 착지하는 것으로 오해되지 않도록 이벤트 바인딩마다 플래그를 추가 플래그를 사용합니다. 라라음음음음음음음음음음음시로 false뒤로 버튼을 누를 때:

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });

위 코드는 나에게 효과가 있었다.모바일 브라우저에서는 사용자가 뒤로 버튼을 클릭했을 때 이전 방문과 같이 페이지 상태를 복원하고 싶었습니다.

Kotlin/JS용 솔루션(반응):

import org.w3c.dom.events.Event
import kotlin.browser.document
import kotlin.browser.window

...
override fun componentDidMount() {
    window.history.pushState(null, document.title, window.location.href)
    window.addEventListener("popstate", actionHandler)
}
...
val actionHandler: (Event?) -> Unit = {
    window.history.pushState(
        null,
        document.title,
        window.location.href
    )
    // add your actions here
}

이 문제에 대한 해결책을 찾고 있었습니다.여기서 몇 가지 답변과 MDN Web Doc 페이지를 바탕으로 간단한 스켈레톤 테스트 html을 작성했습니다.

다음 HTML 및 JavaScript는 복사 및 붙여넣기 및 테스트하기에 충분합니다.

브라우저 버튼 및 앞으로 이동 바로 가기 키와 함께 작동하여 URL에 변경 사항을 추가합니다(경우에 따라 중요).

기존 코드 키포인트에 추가하기에 충분하며 확장도 가능해야 합니다.

<html>
<body>
<div id="p1">Option 1</div>
<div id="p2">Option 2</div>
<div id="p3">Option 3</div>
<div id="p4">Option 4</div>
<div id="c"></div>
<script>
var chg={
    set:function(str){
        var d=document.getElementById("c");
        d.textContent=str;
    },
    go:function(e){
        var s={"p":this.id};
        chg.set(s.p);
        hstry.add(s);
    }
};
var hstry={
    add:function(s){
        var u=new URL(window.location);
        u.searchParams.set("x",s.p);
        window.history.pushState(s,"",u);
    },
    adjust:function(state){
        if(state.p){
            chg.set(state.p);
        }
    }
};
window.onpopstate=function(e){
    console.log("popstate, e.state:["+ JSON.stringify(e.state) +"]");
    hstry.adjust(e.state);
}
window.onload=function(){
    var i,d,a=["p1","p2","p3","p4"];
    for(i=0;i<a.length;i++){
        d=document.getElementById(a[i]);
        d.addEventListener("click",chg.go,false);
    }
}
</script>
</body>
</html>

위의 옵션을 시도해 보았지만, 어느 것도 나에게 맞지 않습니다.여기 해결책이 있습니다.

if(window.event)
   {
        if(window.event.clientX < 40 && window.event.clientY < 0)
        {
            alert("Browser back button is clicked...");
        }
        else
        {
            alert("Browser refresh button is clicked...");
        }
    }

상세한 것에 대하여는, 다음의 링크를 참조해 주세요.http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli

언급URL : https://stackoverflow.com/questions/25806608/how-to-detect-browser-back-button-event-cross-browser

반응형