【问题标题】:Need to click twice to go back in history (using pushState)需要点击两次才能回到历史(使用pushState)
【发布时间】:2014-07-07 12:18:36
【问题描述】:

我有一个包含一些选择字段的页面。 一旦用户更改了选择字段的值,就会使用所有选择字段的值作为状态对象创建一个新的历史对象:

$(".chosen-select-field").chosen().change(function() {
    $(".chosen-select-field").each( function ( index ) {
        parameterNames[index].value = $( this ).val();
    });
    history.pushState(parameterNames, '', newUrl);
});

parameterNames 是一个包含键和值的对象数组,例如

parameterNames.push({key:"name", value:"foobar"});

以下代码会在用户单击浏览器中的后退或前进按钮时恢复状态。它有效,但行为异常。

例如,我更改了三个选择字段(创建三个历史条目)。然后我回去。执行 restoreState 时,一个选择字段会相应更改。但是浏览器本身在历史记录中的位置保持不变(不能前进,仍然是相同数量的回溯历史条目)。

然后我再次单击后退按钮。这次状态对象与我单击的列表时间相同。不过,浏览器会在历史记录中向后移动一个条目。

第三次单击后退按钮时,下一个选择字段会更改,但浏览器会再次保持该状态,除非我第四次单击。

谁能解释我做错了什么?

var restoreState = function(event) {
    event = event.originalEvent;
    parameterNames = event.state;
    $(".chosen-select-field").each( function ( index ) {
        if ($( this ).val() != parameterNames[index].value){
            $( this ).val(parameterNames[index].value).change();
            $( this ).trigger('chosen:updated');
        }
    });
};

// Bind history events
$(window).bind("popstate",restoreState);

【问题讨论】:

  • 在 popstate(例如返回)上,您正在调用“restoreState”,它循环字段,并可能调用 .change(),它再次执行 history.pushState。如果 popstate 事件被触发,我建议执行 replaceState。

标签: javascript jquery html browser-history html5-history


【解决方案1】:

当 popstate 事件被触发并循环选择字段时,如果满足$( this ).val() != parameterNames[index].value 条件,则当前选择值将被更改,但也会触发 change 事件,进而再次调用将新状态推入历史的功能。这样,如果你回到历史,你会得到相同的状态对象。

因此,解决方案是检查是否触发了 popstate 事件,如果是,则不要调用 history.pushState,而是调用 history.replaceState

function handleHistoryStates(popstateEventWasFired = false) {
    $(".chosen-select-field").each( function ( index ) {
        parameterNames[index].value = $( this ).val();
    });
    
    if (popstateEventWasFired) {
        history.replaceState(parameterNames, '', newUrl);
    } else {
        history.pushState(parameterNames, '', newUrl);
    }
}

$(".chosen-select-field").chosen().change(handleHistoryStates);


var restoreState = function(event) {
    event = event.originalEvent;
    parameterNames = event.state;
    $(".chosen-select-field").each( function ( index ) {
        if ($( this ).val() != parameterNames[index].value){
            $( this ).val(parameterNames[index].value);
            handleHistoryStates(true);
            $( this ).trigger('chosen:updated');
        }
    });
};

// Bind history events
$(window).bind("popstate",restoreState);

【讨论】:

    【解决方案2】:

    我猜你是Pushing当你到达状态时的当前状态,而不是当你到达当前状态时你推送上一个状态.. 这就是为什么当你第一次按下后退按钮时你会弹出当前状态,而你需要弹出前一个状态并去那里......

    let boxes = Array.from(document.getElementsByClassName('box'));
    
    function selectBox(id) {
      boxes.forEach(b => {
        b.classList.toggle('selected', b.id === id);
      });
    }
    
    boxes.forEach(b => {
      let id = b.id;
      b.addEventListener('click', e => {
        history.pushState({
          id
        }, `Selected: ${id}`, `./selected=${id}`)
        selectBox(id);
      });
    });
    
    window.addEventListener('popstate', e => {
      selectBox(e.state.id);
    });
    
    history.replaceState({
      id: null
    }, 'Default state', './');
    .boxes {
      display: flex;
    }
    
    .desc {
      width: 100%;
      display: flex;
      align-items: center;
      padding: 3rem 0;
      justify-content: center;
      font-weight: bold;
    }
    
    .box {
      --box-color: black;
      width: 50px;
      height: 50px;
      margin: 20px;
      box-sizing: border-box;
      display: block;
      border-radius: 2px;
      cursor: pointer;
      color: white;
      background-color: var(--box-color);
      border: 5px solid var(--box-color);
      font-size: 14px;
      font-family: sans-serif;
      font-weight: bold;
      text-align: center;
      line-height: 20px;
      transition: all 0.2s ease-out;
    }
    
    .box:hover {
      background-color: transparent;
      color: black;
    }
    
    .box.selected {
      transform: scale(1.2);
    }
    
    #box-1 {
      --box-color: red;
    }
    
    #box-2 {
      --box-color: green;
    }
    
    #box-3 {
      --box-color: blue;
    }
    
    #box-4 {
      --box-color: black;
    }
    <div class="boxes">
      <div class="box" id="box-1">one</div>
      <div class="box" id="box-2">two</div>
      <div class="box" id="box-3">three</div>
      <div class="box" id="box-4">four</div>
    </div>
    <div class="desc">
      Click to select Each box and u can navigate back using browser back button
    </div>

    检查此代码笔:https://codepen.io/AmalNandan/pen/VwmrQJM?editors=1100

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-08
      • 2023-03-17
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-05
      相关资源
      最近更新 更多