【问题标题】:How to avoid duplicate push on top of History Api Stack如何避免在 History Api Stack 顶部重复推送
【发布时间】:2021-01-26 07:44:42
【问题描述】:

我遇到了在堆栈顶部推送重复的问题 History api 堆栈

假设我有点击模式的用户界面(1 到 4 页,它可以根据用户的选择是随机的)

问题:我想以与history api 顶部单击相同的方式推送所有页面而不重复,这样当浏览器前进时,单击后退按钮的 url 应该改变(右现在需要点击 2 次)

这是我的项目设置的样子(点击同一页面 2 次查看实际问题):

$('li').on('click',function(){
   var baseUrl = location.href;  //'http://www.siliconvalley.com/pages/';//it can be current url also
   var page = $(this).attr('data-page');
   var urlObj = new URL(baseUrl);
   urlObj.searchParams.append('page',page);
   $('#loadedPageContainer').prepend(`<p>${urlObj.href}</p>`);
   try{
       history.pushState({}, null, urlObj.href); //wanted to avoid duplicate on top of history api stack
   }catch(e){}

});

window.addEventListener('popstate', function(e){    
       console.log('page navigated',e);  // called 2 times in my project
      //navigateToCurrentUrlRoute();
});
ul{
  list-style:none;
  display:flex;
  justify-content: space-evenly;
}

ul li{
    border: 1px solid red;
    padding: 50px;
    cursor:pointer;
}

#loadedPageContainer{
    //display: flex;
    width: 500px;
    height: 200px;
    box-shadow: 0 1px 2px 3px #c7c7c7;
      margin: 0 auto;
/*   overflow:auto; */
  overflow-y:auto;
      line-height: 38px;
   padding:15px;
}

#loadedPageContainer p{
      box-shadow: 0 1px 2px 0px #dee5ea;
}

#loadedPageContainer p:first-child {
    box-shadow: 0 4px 2px 1px #de004b;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li data-page="1">page 1</li>
  <li data-page="2">page 2</li>
  <li data-page="3">page 3</li>
  <li data-page="4">page 4</li>
</ul>
<p>Please click same pages 2 or 3 times to see actual issue below or in url on forward,backward browser button click</p>
<div id="loadedPageContainer">
  
</div>

注意:只有history api 堆栈的顶部不能有重复项

为了更好地查看这里是一个codepen链接:https://codepen.io/eabangalore/pen/KKgOwgN 请帮助我提前谢谢!

【问题讨论】:

    标签: javascript jquery url navigation


    【解决方案1】:

    为避免 History API 堆栈中的重复条目,有必要将当前页面地址与将要使用 History API 添加的新地址进行比较。

    此外,您需要使用urlObj.searchParams.set('page', page) 而不是urlObj.searchParams.append('page', page),因为append 实际上不会更改查询参数nameappend 只是在 URL 中添加新的同名查询参数。

    试试这个代码,它一定有帮助:

    $('li').on('click', function () {
        var baseUrl = location.href;
        var page = $(this).attr('data-page');
        var urlObj = new URL(baseUrl);
    
        urlObj.searchParams.set('page', page); // this line was changed
    
        if (urlObj.href !== baseUrl) { // href check was added
            $('#loadedPageContainer').prepend(`<p>${urlObj.href}</p>`);
            try {
                history.pushState({}, null, urlObj.href);
            } catch (e) {}
        }
    });
    
    window.addEventListener('popstate', function (e) {
        console.log('page navigated', e);
    });
    

    【讨论】:

      【解决方案2】:

      您的问题是您使用了.append 它添加了第二个和第三个参数,依此类推。你明白吗?所以看看这个:

      $('li').on('click',function(){
         var baseUrl = location.href;  //'http://www.siliconvalley.com/pages/';//it can be current url also
         var page = $(this).attr('data-page');
         var urlObj = new URL(baseUrl);
         urlObj.searchParams.set('page',page); // use set instead of append
         $('#loadedPageContainer').prepend(`<p>${urlObj.href}</p>`);
         try{
             history.pushState({}, null, urlObj.href); //wanted to avoid duplicate on top of history api stack
         }catch(e){}
      
      });
      
      window.addEventListener('popstate', function(e){    
             console.log('page navigated',e);  // called 2 times in my project
            //navigateToCurrentUrlRoute();
      });
      ul{
        list-style:none;
        display:flex;
        justify-content: space-evenly;
      }
      
      ul li{
          border: 1px solid red;
          padding: 50px;
          cursor:pointer;
      }
      
      #loadedPageContainer{
          //display: flex;
          width: 500px;
          height: 200px;
          box-shadow: 0 1px 2px 3px #c7c7c7;
            margin: 0 auto;
      /*   overflow:auto; */
        overflow-y:auto;
            line-height: 38px;
         padding:15px;
      }
      
      #loadedPageContainer p{
            box-shadow: 0 1px 2px 0px #dee5ea;
      }
      
      #loadedPageContainer p:first-child {
          box-shadow: 0 4px 2px 1px #de004b;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <ul>
        <li data-page="1">page 1</li>
        <li data-page="2">page 2</li>
        <li data-page="3">page 3</li>
        <li data-page="4">page 4</li>
      </ul>
      <p>Please click same pages 2 or 3 times to see actual issue below or in url on forward,backward browser button click</p>
      <div id="loadedPageContainer">
        
      </div>

      该代码无需重复参数即可工作。如果您想避免重复推送(我认为这是您的主要问题),您必须检查 URL 是否已更改:

      $('li').on('click',function(){
         var baseUrl = location.href;  //'http://www.siliconvalley.com/pages/';//it can be current url also
         var page = $(this).attr('data-page');
         var urlObj = new URL(baseUrl);
         urlObj.searchParams.set('page',page); // use set instead of append
         $('#loadedPageContainer').prepend(`<p>${urlObj.href}</p>`);
         if (baseUrl != urlObj) { // check url change
             try{
                 history.pushState({}, null, urlObj.href); //wanted to avoid duplicate on top of history api stack
             }catch(e){}
         }
      });
      
      window.addEventListener('popstate', function(e){    
             console.log('page navigated',e);  // called 2 times in my project
            //navigateToCurrentUrlRoute();
      });
      ul{
        list-style:none;
        display:flex;
        justify-content: space-evenly;
      }
      
      ul li{
          border: 1px solid red;
          padding: 50px;
          cursor:pointer;
      }
      
      #loadedPageContainer{
          //display: flex;
          width: 500px;
          height: 200px;
          box-shadow: 0 1px 2px 3px #c7c7c7;
            margin: 0 auto;
      /*   overflow:auto; */
        overflow-y:auto;
            line-height: 38px;
         padding:15px;
      }
      
      #loadedPageContainer p{
            box-shadow: 0 1px 2px 0px #dee5ea;
      }
      
      #loadedPageContainer p:first-child {
          box-shadow: 0 4px 2px 1px #de004b;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <ul>
        <li data-page="1">page 1</li>
        <li data-page="2">page 2</li>
        <li data-page="3">page 3</li>
        <li data-page="4">page 4</li>
      </ul>
      <p>Please click same pages 2 or 3 times to see actual issue below or in url on forward,backward browser button click</p>
      <div id="loadedPageContainer">
        
      </div>

      popstate 事件现在也应该每次点击只调用一次。

      【讨论】:

        【解决方案3】:

        我不确定我是否理解这个问题。

        我是这样理解的。您有两个上下文,我们可以将其称为“历史”。一种上下文是页面 url 参数(例如 &page=1?page=2 等)。我将在这种情况下将历史称为 PAGE STATES。第二个上下文是浏览器理解的历史状态。我将在这种情况下将历史称为 HISTORY STACK。

        运行 sn-p 并让我知道它是否提供了您正在寻找的行为。如果没有,我已经让 cmets 关于我编写的代码要做的事情,以及每次编辑的目标是什么。

        以下是代码功能的简明英文预览:

        它将 1 到 4 个项目添加到您的 PAGE STATES 中,没有重复项,并且它允许 HISTORY STACK 中的任意数量的状态,没有立即重复项。

        如果您在第 1 页和第 2 页之间多次单击,则 PAGE STATE 中将有 2 个项目。如果您在页面 1 到 3 之间单击,则 PAGE STATE 中将有 3 个项目,依此类推。

        由于我们不会在 PAGE STATE 中留下重复项,也不会删除任何历史记录,因此如果所有 4 个页面都被访问过,那么 PAGE STATE 中将始终有 4 个项目,最近访问最少的页面来自从右到左 - 最近访问的页面作为第一个 url 参数显示。就历史堆栈而言,历史堆栈中的条目将与页面状态中的更改一样多。我希望我以一种有意义的方式呈现了这一点。

        /*
         * Edit #1: Adding PARAM STATE / page array and previous page marker
         */
        let pageArray = []; // array holding page param history (aka 'PARAM STATES')
        let prevPage; // most recently visited page
        /* END Edit #1 */
        
        $('li').on('click',function(){
          var baseUrl = 'http://www.siliconvalley.com/pages/';//it can be current url also
          var page = $(this).attr('data-page');
          var urlObj = new URL(baseUrl);
        
          /*
           * Edit #2: Using new variables above to hold/dictate non-duplicate states.
           */
          // If 'revisiting' previous (current) page...
          if (page === prevPage){
            return; // ...keep both STACK and PARAM STATES as they are...
          }
          else prevPage = page; // ...else continue.
           
          pageArray.unshift(page); // Set current page as first in PARAM STATES...
          pageArray = [...new Set(pageArray)]; // ...remove duplicates...
          pageArray = pageArray.slice(0,4); // ...and limit PARAM STATES to 4 pages.
          urlObj.searchParams.delete('page');// Delete previous PARAM STATE.
        
          /* When we now create the search param items using PARAM STATE...
           *
           * 1.) We've assured PARAM STATE has no duplicates.
           * 2.) We've allowed up to 4 states to be presented in PARAM STATES.
           * 3.) We've kept immediate/repeat/duplicate history states out of the
           *     HISTORY STACK so that clicking 'back' in a browser does not result
           *     in staying on the same page / in the same state.
           */
           pageArray.forEach((item) => {urlObj.searchParams.append('page',item)}); 
           /* END Edit #2 */
        
           try{
             history.pushState({}, null, urlObj.href); //wanted to avoid duplicate on top of history api stack 
          }catch(e){}
          $('#loadedPageContainer').prepend(`<p>${urlObj.href}</p>`);
        });
        
        window.addEventListener('popstate', function(e){    
               console.log('page navigated',e);  // called 2 times in my project
              //navigateToCurrentUrlRoute();
        });
        ul{
          list-style:none;
          display:flex;
          justify-content: space-evenly;
        }
        
        ul li{
            border: 1px solid red;
            padding: 50px;
            cursor:pointer;
        }
        
        #loadedPageContainer{
            //display: flex;
            width: 500px;
            height: 200px;
            box-shadow: 0 1px 2px 3px #c7c7c7;
              margin: 0 auto;
        /*   overflow:auto; */
          overflow-y:auto;
              line-height: 38px;
           padding:15px;
        }
        
        #loadedPageContainer p{
              box-shadow: 0 1px 2px 0px #dee5ea;
        }
        
        #loadedPageContainer p:first-child {
            box-shadow: 0 4px 2px 1px #de004b;
        }
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <ul>
          <li data-page="1">page 1</li>
          <li data-page="2">page 2</li>
          <li data-page="3">page 3</li>
          <li data-page="4">page 4</li>
        </ul>
        <p>Please click same pages 2 or 3 times to see actual issue below or in url on forward,backward browser button click</p>
        <div id="loadedPageContainer">
          
        </div>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-05-07
          • 1970-01-01
          • 1970-01-01
          • 2021-06-28
          • 2015-10-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多