pushState / popstate的奇怪问题 - 初始页面似乎被“推”了两次

时间:2015-04-24 14:31:11

标签: javascript pushstate

我对pushState / popstate有一个奇怪的问题,我的初始页面似乎保存了两次。

没有例子就很难解释。

类似的东西:

  1. 当前页面是www.bing.com
  2. 将我的网址复制/粘贴到网址栏和网页加载
  3. 点击页面上的链接(此链接会触发AJAX请求,然后操纵DOM以显示检索到的数据。)
  4. 按下后退按钮,将我带到与步骤2中相同的页面
  5. 再次按回按钮,但我仍然和step2 / 4
  6. 在同一页面上
  7. 再次按回按钮,这将我带回www.bing.com
  8. 正如您所看到的,我需要按两次后退按钮才能让我回到www.bing.com,只需要1。

    我的页面的简短说明(代码位于页面底部):

    1. 页面加载时,通过AJAX检索下拉列表选择的初始列表并填充选择标记。

    2. 用户可以选择单击3个链接来确定下拉列表选择的内容。示例:如果单击选项B链接,则会从步骤1触发相同的AJAX,但仅检索适用于选项B的数据。

    3. 用户从下拉列表中进行选择并按下搜索。这会触发另一个AJAX函数,该函数检索相关数据并在 mysearchresults div中显示格式化信息。

    4. 我尝试使用pushState进行放置(例如在AJAX调用之前或之后),现在放置似乎是给我带来最少问题的放置。虽然我确实遇到了上面提到的问题。

    5. 这是我的代码。我不得不删除很多代码/函数,使其简短易读,但请确保AJAX调用/数据显示正常工作。

      <div id="content">
          <p>
              <a class="coursetype" href="#" data-type="B">Option B</a>
              | <a class="coursetype" href="#" data-type="H">Option H</a>
              | <a class="coursetype" href="#" data-type="BG">Option BG</a>
          </p>
      
          <form id="myform">
              <label class="formlabel" for="course">Select your course</label>
              <br /><select id="course" name="course"></select>
              <button id="searchbutton" type="button">Search Me</button>
          </form>
      
          <div id="mysearchresults"></div>
      </div>
      
      $(document).ready(function() {
          var onClickCourseTypeHandler = function(event) {
              event.preventDefault();
      
              getCourses({ type:$(event.target).data("type") });
      
              window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", main?type="+pagevars.type);
          }
      
          var onClicksearchbuttonHandler = function(event) {
              if ($("#coursecode").val().length > 0) {
                  searchDB({ course:$("#course").val() });
      
                  window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", "/main?&course="+$("#course").val());
              }
          };
      
          $(document).on("click", ".coursetype", onClickCourseTypeHandler);
      
          $(document).on("click", "#searchbutton", onClicksearchbuttonHandler);
      
          try {
              window.addEventListener("popstate", function(event) {
                  if (event.state) {
                      $("#content").html(event.state.html);
      
                      if (event.state.coursecode.length > 0) {
                          if ($("#course option[value='" + event.state.course + "']").length > 0) {
                              $("#course").val(event.state.course);
                          } else {
                              $("#course option:first-child").attr("selected", "selected");
                          }
                      }
                  }
              });
          } catch(exception) {
          }
      
          onLoad();
      
          function onLoad() {
              getCourses({ type:"" });
      
              window.history.pushState({ html:$("#content").html(), course:dbvars.course }, "", "/main");
          }
      
          function searchDB(parameters) {
              $.ajax({
                  url: baseurl+"/searchDB"
                  , cache: false
                  , dataType: "json"
                  , data: { format:"json", course:parameters.course }
                  , success: function(data, status) {
                      parameters.data = data;
                      displaySearchResults(parameters);
                  }
              });
          }
      
          function getCourses(parameters) {
              if (typeof(parameters.cacheflag) === "undefined") { parameters.cacheflag = false; };
      
              $.ajax({
                  url: baseurl+"/getCourses"
                  , cache: parameters.cacheflag
                  , dataType: "json"
                  , data: { format:"json", coursetype:parameters.type }
                  , success: function(data, status) {
                      parameters.data = data;
                      populateCourses(parameters);
                  }
              });
          }
      });
      

4 个答案:

答案 0 :(得分:8)

当您加载页面时,它会被添加到历史记录中,因此当您执行func a(sender: AnyObject) {} textField.addTarget(self, action: "a:", forControlEvents: .EditingDidEndOnExit) 时,它会再次添加。 尝试在onload函数中将history.pushState替换为history.pushState

答案 1 :(得分:4)

我注意到你在你的href中使用哈希(#)。尝试将a hrefs中的哈希值(#)更改为Javascript:void(0)。


    Javascript:void(0);

href中的哈希(#)将对pushState / popState产生影响。

答案 2 :(得分:2)

在页面加载时将对象文字传递给pushState()。这样您就可以随时返回到第一个创建的pushState。

添加到DOM准备

var obj = { html: '', coursecode: '' };

try {
    window.history.pushState({
        html: $("#content").html(),
        coursecode: $("#coursecode").val()
    }, 'just content or variable', window.location.href);
} catch (e) {
    console.log(e);
}

在你的事件处理程序中推送状态:

var onClicksearchbuttonHandler = function(event) {
    if ($("#coursecode").val().length > 0) {
        searchDB({ course:$("#course").val() });

        obj.html = $("#content").html();
        obj.coursecode = $("#coursecode").val();
        window.history.pushState(obj, "", "/main?&course="+$("#course").val());
    }
};

返回原始状态时:

$(window).on('popstate', function (ev) {
    var originalState = ev.originalEvent.state || obj.html;
    if (!originalState) {
        // no history
        // do something
        return;
    } else {
        // do something
    }
});

答案 3 :(得分:0)

我发现这对于单页应用程序非常有效

我决定使用这个方便的小功能,该功能允许将一个项目在历史记录为空时或仅在未通过按后退按钮调用的情况下将其推入历史记录

(消除重复项,因此您不必两次单击后退按钮)

Client.GetObjectAsync(BucketName, FileName, (responseObj) =>
        {
        //print("about to get json");

            if (responseObj.Exception == null) print("exception not null"); else print(responseObj.Exception.Message);
            string data = null;
            var resp = responseObj.Response;
            if (resp == null)
            {
            //print("null");
            }
            else
            {
            //print("not null");
            }
        //print(resp.ContentLength);

            if (resp.ResponseStream != null)
            {
                print("before StreamReader");


                using (StreamReader reader = new StreamReader(resp.ResponseStream))
                {
                //print("In StreamReader");
                data = reader.ReadToEnd();
                //print("got json");
                }



            /**
            string fp = Application.dataPath + "\\unitydata.txt";
            using (var fs = System.IO.File.Create(@fp))
            {
                byte[] buffer = new byte[81920];
                int count;
                while ((count = resp.ResponseStream.Read(buffer, 0, buffer.Length)) != 0)
                    fs.Write(buffer, 0, count);
                fs.Flush();
            }
            **/

           // }
           // else
           // {
           //     print("response is null");
           // }
           // print("JSON CONTENT: " + data);
           // float[] fres = parseVectors(data);
           // for (int i = 0; i < fres.Length; i++) print(fres[i] + " ");
           // responseObj.ToString();
       // });

使用:historyPush(“ Page1”)

然后我在popstate侦听器函数中使用了switch大小写,将内容加载回页面:

function historyPush(siteLocation){
    if (!history.state || history.state.sitelocation != siteLocation){
      var stateObj = { sitelocation: siteLocation };
      history.pushState(stateObj, (siteLocation + " page"), ("index.html"));
    }
}

在每种情况下它都不是完美的,例如,如果您的站点是300种不同的情况,则您可能希望使用popstate侦听器另辟route径。但是对于小型站点,它可以很好地完成工作。