如何避免在 popstate 事件处理程序中调用 history.pushState?

How to avoid calling history.pushState in the popstate event handler?

假设我们有一个 <p:commandLink action="…" onclick="history.pushState(…)"> 对页面状态进行了重要更改。 Primefaces 5.1 生成此 HTML:

<a id="link1" href="#"
    onclick="history.pushState( {currentStateKeyWord: 'state1'},'','state1');
             PrimeFacesGeneratedFunction(stuff);">Click me for state 1</a>
<a id="link2" href="#"
    onclick="history.pushState( {currentStateKeyWord: 'state2'},'','state2');
             PrimeFacesGeneratedFunction(stuff);">Click me for state 2</a>

popstate 事件处理程序中,我们必须根据 pushState 中作为第一个参数推送的对象恢复状态。使用 JQuery:

jQuery(document).ready(function(jQuery) {
    jQuery(window).bind('popstate', function(event) {
        if ((event.originalEvent.state!==null)
             && (event.originalEvent.state.currentStateKeyWord!==undefined)) {
            switch (event.originalEvent.state.currentStateKeyWord) {
                case 'state1':
                    jQuery("#link1").click();
                    break;
                case 'state2':
                    jQuery("#link2").click();
                    break;
                 default:
                    console.error("Unknown state");
            }
        }
    }
}

为什么这不起作用:使用jQuery("#link1").click();强制link像用户点击它一样工作,这很好,但不幸的是,popstate 事件处理程序不能调用 history.pushState(在 onclick 内)。在 Firefox 中,此代码破坏了前进按钮,这是不可取的。

问题:正确编写对 history.pushStatepopstate 事件处理程序的调用的最简单方法是什么,同时考虑到任何我们这样做,popstate 必须触发对 PrimeFacesGeneratedFunction(stuff)?

的调用

谢谢!

昨天我以为解决方案应该在客户端,和往常一样,今天早上醒来我的想法完全不同。

我原来的 JSF 代码是:

<p:commandLink action="#{associateBean.setState('state1')}" 
       onclick="history.pushState('{currentStateKeyWord: 'state1'}','','state1')"
       update="somePanel"/>

<p:commandLink action="#{associateBean.setState('state2')}" 
       onclick="history.pushState('{currentStateKeyWord: 'state2'}','','state2')"
       update="somePanel"/>

如上所述,问题在于 Primefaces 生成了一个 HTML 锚点(a)并使用 onclick 属性调用我自己的 onclick 代码(history.pushState) 和其他一些与 action 属性 (PrimefacesGeneratedFunction('stuff')) 的内容相关的函数。

解决方案不是调整JavaScript,而是使用<p:remoteCommand>action内容移出[=21] =].

新的 JSF 代码是:

<p:remoteCommand name="setState1"
     actionListener="#{associateBean.setState('state1')}"  
     update="somePanel"/>
<p:commandLink onclick="setState1();
     history.pushState('{currentStateKeyWord: 'state1'}','','state1')"/>

<p:remoteCommand name="setState2"
    actionListener="#{associateBean.setState('state2')}"
    update="somePanel"/>
<p:commandLink onclick="setState2();
    history.pushState('{currentStateKeyWord: 'state2'}','','state2')"/>

现在 popstate 事件处理程序引用 <p:remoteCommand name> 属性,而不是在原始 link:

上调用 click()
jQuery(document).ready(function(jQuery) {
    jQuery(window).bind('popstate', function(event) {
        if ((event.originalEvent.state!==null)
             && (event.originalEvent.state.currentStateKeyWord!==undefined))     {
            switch (event.originalEvent.state.currentStateKeyWord) {
                case 'state1':
                    setState1();
                    break;
                case 'state2':
                    setState2();
                    break;
                 default:
                    console.error("Unknown state");
            }
        }
    }
}

希望这对某人有所帮助。