繁体   English   中英

停止在 hashchange 上触发 popstate

[英]stop firing popstate on hashchange

我正在使用历史记录 API 并使用 push 和 pop state。我想在某些情况下停止触发 popstate 事件,我只将 hash 附加到 URL。例如,在某些情况下,单击锚点时它会将#附加到URL 并立即触发 popstate)我想避免所有将##somehasvalue附加到 URL 并阻止 popstate 触发的情况。 我正在使用查询参数维护 URL,并且我没有任何需要在 URL 中使用#触发 popstate 事件的场景。

这是我的代码。

if (supportsHistoryApi()) {

    window.onpopstate = function (event) {
    var d = event.state || {state_param1: param1, state_param2: param2};                       
    var pathName = window.location.pathname,
        params   = window.location.search;

    loadData(event, pathName + params, d.state_param1, d.state_param2);

}

据我发现,不幸的是,您无法阻止 popstate 触发。

您可以做的是检查event.state对象。 哈希更改时将为空。 所以我建议添加一个

if(event.state === null) {
   event.preventDefault();
   return false;
}

一开始就发送给您的 popstate 事件处理程序。 我认为这是防止在哈希更改时触发 popstate 处理代码的最佳方法,但我很想知道是否有其他解决方案。

我有办法!

  • 当 popstate 事件调用时,检查路径名是否已更改,或者只是哈希更改。 在下面观看它对我的作用:
        window.pop_old = document.location.pathname;
        window.pop_new = '';
        window.onpopstate = function (event) {

            window.pop_new = document.location.pathname;

            if(pop_new != pop_old){

                //diferent path: not just the hash has changed

            } else {

                //same path: just diferent hash

            }

            window.pop_old = pop_new; //save for the next interaction

        };

如果有人仍然需要这个:

var is_hashed = false;

$(window).on('hashchange', function() {
    is_hashed = true;
});

window.addEventListener('popstate', function(e){
    // if hashchange
    if (is_hashed) {
        e.preventDefault();
        // reset
        is_hashed = false;
        return false;
    }

    // Your code to handle popstate here
    ..................
});

这很简单。

为了防止在单击带有散列的链接后popstate事件,您必须消除单击链接的popstate - 这是将散列添加到浏览器地址栏。

基本上你必须为click事件创建处理程序,检查点击是否在你想要阻止哈希出现在 URL 中的元素上,并通过调用event.preventDefault();来阻止哈希出现event.preventDefault(); 在处理程序中。

下面是代码示例:

/**
 * This your existing `onpopstate` handler.
 */
window.onpopstate = function(e) {
    // You could want to prevent defaut behaviour for `popstate` event too.
    // e.preventDefault(); 
    // Your logic here to do things. 

    // The following reload is just an example of what you could want to make
    // in this event handler.
    window.location.reload();
};

/**
 * This is the `click` event handler that conditionally prevents the default
 * click behaviour.
 */
document.addEventListener('click', function(e) {
    // Here you check if the clicked element is that special link of yours.
    if (e.target.tagName === "A" && e.target.hash.indexOf('#the-link-i-want-make-discernable') > -1) {
        // The 'e.preventDefault()' is what prevent the hash to be added to
        // the URL and therefore prevents your 'popstate' handler to fire.
        e.preventDefault();
        processMySpecialLink(e, e.target);
    }

});

/**
 * Just an example of the link click processor in case you want making something
 * more on the link click (e.g. smooth scroll to the hash).
 */
function processMySpecialLink(e, target) {
    // Make things here you want at user clicking your discernable link.
}

这是匹配的 HTML 标记:

<!-- Somewhere in the markup -->
<span id="the-link-i-want-make-discernable"></span>
<!-- Some markup -->
<a href="#the-link-i-want-make-discernable">My Special Link</a>
<!-- Another markup -->
<a href="#just-common-link">Any other link</a>

这一切都做了上面描述的:防止特殊哈希链接的默认行为。 作为副作用,它不会popstate事件,因为对于单击#the-link-i-want-make-discernable哈希链接的特殊情况,没有将哈希添加到 URL。

我在 SPA 中遇到了同样的问题。
我通过检查当前的 URL 和新的 URL 是否相同来修复此问题 - 从技术上讲,我不会阻止 popstate ,但如果 hash 仅更改,我会阻止获取。

所以,当页面加载时,我得到当前的 URL。 它必须是 var 才能是全局的:

var currentURL = window.location.origin + window.location.pathname + window.location.search;

然后,当触发历史更改事件时(点击链接,点击本机浏览器按钮“后退”“前进”),我检查当前 URL 和新 URL 是否相同(忽略哈希)。
如果 URL 相同我返回,否则我更新当前 URL。

let newURL = window.location.origin + window.location.pathname + window.location.search;
if ( currentURL == newURL ) return;
currentURL = newURL;

此外,您还可以看到controller代码 我添加它是为了能够在用户快速单击几次“后退”或“前进”时停止加载,所以一些请求启动 - 但我只需要加载最后一个。

当 URL 更改时加载 html 文件的完整解决方案(当 hash 仅更改时忽略),推送到历史记录,以及可用的“后退”和“前进”按钮。

// get current URL when page loaded.
var currentURL = window.location.origin + window.location.pathname + window.location.search;

// function which load html.
window.xhrRequestDoc = ( currentLink, pushToHistory = true, scrollTo = 'body' ) => {
    if ( pushToHistory ) {
        history.pushState( null, null, currentLink );
    }

    // get new URL
    let newURL = window.location.origin + window.location.pathname + window.location.search;

    // return if hash only changed
    if ( currentURL == newURL ) return;

    // update URL
    currentURL = newURL;

    document.body.classList.add( 'main_loading', 'xhr_in_progress' );

    // create controler to stop loading - used when user clicked a few times 'back' or 'forward'.
    controller = new AbortController();
    const signal = controller.signal;

    fetch( currentLink, { signal: signal })
        .then( response => response.text() )
        .then( function( html ) {

            // initialize the DOM parser and parse as html
            let parser = new DOMParser();
            let doc = parser.parseFromString( html, "text/html" );

            // insert data and classes to 'body'
            document.body.innerHTML = doc.querySelector( 'body' ).innerHTML;
        } );
}

window.addEventListener( 'popstate', () => {
    // if user clicked a few times 'back' or 'forward' - process last only
    if ( document.querySelector( '.xhr_in_progress' ) ) controller.abort();

    // run xhr
    xhrRequestDoc( location.href, false );
})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM