首頁  >  文章  >  web前端  >  基於h5的history改善ajax清單請求體驗

基於h5的history改善ajax清單請求體驗

亚连
亚连原創
2018-05-24 14:47:541588瀏覽

這篇文章主要介紹了基於h5的history改善ajax列表請求體驗的相關資料,需要的朋友可以參考下

信息比較豐富的網站通常會以分頁顯示,在點“下一頁」時,很多網站都採用了動態請求的方式,避免頁面刷新。雖然大家都是ajax,但從一些小的細節還是 可以分辨優劣。一個小的細節是能否支援瀏覽器「後退」和「前進「鍵。本文討論兩種方法,讓瀏覽器可以後退和前進,或者說讓ajax就像重定向到新頁面一樣 擁有能夠返回到上一頁或前進到下一頁。

      資料實現分頁顯示,最簡單的做法是在網址後面加上多個page的當數,點「下一頁」時,讓網頁重新導向到page 1的新位址。例如新浪的新聞網就 是這麼做的,透過改變網址實現:index_1、index_2、index_3…。但是如果這個清單並不是頁面的主體部分,或者頁面的其它部分有很多圖片等豐富元素,例如導航是一個很大的slider,再使用這樣的方式,整個頁面會閃爍得厲害,並且很多資源得重新載入.所以使用ajax請求,動態改變 DOM。

      但是普通的動態的請求不會使網址發生變化,用戶點了下一頁,或者點了第幾頁,想要返回到上一個頁面時,可能會去點瀏覽器的返回鍵,這樣就導致返回的時候不是返回到原先查看的頁面了,而是上一個網址了。例如央視的新聞網就是這樣的。以下從ajax請求開始說起,以一個完整的案例進行分析。

      做了一個demo

   首先,寫一個請求:

 //当前第几页
  var pageIndex = 0;
  //请求函数
  function makeRequest(pageIndex){
    var request = new XMLHttpRequest();
    request.onreadystatechange = stateChange;
    //请求传两个参数,一个是当前第几页,另一个是每页的数据条数
    request.open("GET", "/getBook?page=" + pageIndex + "&limit=4", true);
    request.send(null);
    function stateChange(){
      //状态码为4,表示loaded,请求完成
      if(request.readyState !== 4 ){
        return;
      }
      //请求成功
      if(request.status >= 200 && request.status < 300 || request.status === 304){
        var books = JSON.parse(request.responseText);
        renderPage(books); 
      }
    }
  }

     拿到資料後進行渲染:

  function renderPage(books){
    var bookHtml = 
      "<table>" +
      "  <tr>" +
      "    <th>书名</th>" +
      "    <th>作者</th>" +
      "    <th>版本</th>" +
      "  </tr>";
    for(var i in books){
      bookHtml += 
        "<tr>" +
        "  <td>" + books[i].book_name + "</td>" +
        "  <td>" + books[i].author + "</td>" +
        "  <td>" + books[i].edition + "</td>" +
        "</tr>";
    }
    bookHtml += "</table>";
    bookHtml += 
      "<button>上一页</button>" + 
      "<button onclick=&#39;nextPage();&#39;>下一页</button>";
    var section = document.createElement("section");
    section.innerHtml = bookHtml;
    document.getElementById("book").appendChild(section); 
  }

這樣一個基本的ajax請求就搭起來了,然後再響應「下一頁」按鈕:

  function nextPage(){
    //将页面的index加1
    pageIndex++;
    //重新发请求和页面加载
    makeRequest(pageIndex);
  }

到此,如果不做任何處理的話,就不能夠發揮瀏覽器返回、前進按鈕的作用。

      若能夠偵測使用者點擊了後退、前進按鈕的話,就可以做些文章。 h5就是增加了這麼一個事件window.onpopstate,當使用者點擊那兩個按鈕就會觸 發這個事件。但是光偵測到這個事件是不夠的,還得能夠傳些參數,也就是說回到之前那個頁面的時候得知道那個頁面的pageIndex。透過 history的pushState方法可以達到這個目的,pushState(pageIndex)將目前頁的pageIndex存起來,再回到這個 頁面時取得到這個pageIndex。 pushState的參數如下:

window.history.pushState(state, title, url);

      其中state為object{},用來存放目前頁面的數據,title標題沒有太大的作用,url為目前頁面的url,一旦更改了這個url,瀏覽器網址列的位址也會跟著改變。

      於是,要求下一頁資料的nextPage函數裡面,加上多一步操作:

  function nextPage(){
    pageIndex++;
    makeRequest(pageIndex);
    //存放当前页面的数据
    window.history.pushState({page: pageIndex}, null, window.location.href); 
  }

然後監聽popstate事件:

  //如果用户点击返回或者前进按钮
  window.addEventListener("popstate", function(event){
    var page = 0;
    //由于第一页没有pushState,所以返回到第一页的时候是没有数据的,因此得做下判断
    if(event.state !== null){
      page = event.state.page;
    }
    makeRequest(page); 
    pageIndex = page;
  });

     state資料透過event傳進來,這樣就可以得到pageIndex。

但是,這樣實作還有問題,在第二頁的時候如果刷新頁面的話,會發生錯亂,如下所示:首先點下一頁到第二頁,然後刷新頁面,出現第一頁,再點下一頁,出現第二頁,點返回時出現問題,顯示還是第二頁,不是期望的第一頁,直到再次點返回時才是第一頁:

 從右邊的工具列可以發現,點第一次回傳的時候取得的pageIndex仍然是1。對於這種情況,需要分析history模型,如下所示:

 可以理解為對history的操作,瀏覽器有一個佇列,用來存放存取的記錄,包括每個存取的網址還有state資料。一開始,佇列的首指標指向page = 0的位置,點下一頁時,執行了pushState,在這個佇列插入了一個元素,同時透過pushState操作記錄了這個元素的url和state資料。這裡可以看出,pushState的操作最重要的作用還是給history佇列插入元素,這樣瀏覽器的後退按鈕才不是置灰的狀態,其次才是上面說的存放 資料。點後退的時候,隊首指標後退一步指向page = 0的位置,點前進時又前進指向page = 1的位置。

如果在page = 1的位置刷新页面,模型是这个样子的:

在第2步刷新的时候,页面的pageIndex又恢复成默认值0,所以page = 0,显示第一页数据,但是history所用的队列并没有改变。然后再点下一页时,又给这个队列push了一个元素,这个队列就有两个pageIndex 为1的元素,所以必须得两次返回才能回到page = 0的位置,也就是上面说的错乱的情况。

根据上面的分析,这样的实现是有问题的,一但用户不是在page = 0的位置刷新页面,就会出现需要点多次返回按钮才能够回到原先的页面。

所以得在刷新的时候,把当前页的state数据更新一下,用replaceState,替换队列队首指针的数据,也就是当前页的数据。方法是页面初始化时replace一下:

window.history.replaceState({page: pageIndex /*此处为0*/}, null, window.location.href);
这样模型就变成:

但其实用户刷新的时候更希望的是还是显示当前页,而不是回到第一页。一个解决办法是用当前页的window.history.state数据,这个属性浏览器支持得比较晚。在页面初始化时设置pageIndex时就从history.state取:

var pageIndex = window.history.state === null ? 0 : window.history.state.page;

      safari里面的history.state是最近执行pushState传入的数据,因此这个办法在chrome/firefox里面行得通,但是safari行不通。

      第二种办法是借助h5的localStorage存放当前页数:

 //页面初始化,取当前第几页先从localStorage取
  var pageIndex = window.localStorage.pageIndex || 0;

  function nextPage(){
    //将页面的index加1,同时存放在localStorage
    window.localStorage.pageIndex = ++pageIndex;
    //重新发请求和页面加载
    makeRequest(pageIndex);
    window.history.pushState({page: pageIndex}, null, window.location.href); 
  }

  window.addEventListener("popstate", function(event){
    var page = 0;
    if(event.state !== null){
      page = event.state.page;
    }
    makeRequest(page); 
    //点击返回或前进时,需要将page放到localStorage
    window.localStorage.pageIndex = page;
  });

      将页面中所有改变pageIndex的地方,同时放到localStorage。这样刷新页面的时候就可以取到当前页的pageIndex。

      上面的方法都是将pageIndex放到了state参数里,还有一种方法是把它放到第三个参数url里,也就是说通过改变当前页网址的办法。pageIndex从网址里面取:

 //当前第几页
   var pageIndex = window.location.search.replace("?page=", "") || ;
   function nextPage(){
     //将页面的index加
     ++pageIndex;
     //重新发请求和页面加载
     makeRequest(pageIndex);
     window.history.pushState(null, null, "?page=" + pageIndex);
   }

      注意,一旦执行了第8行的pushState,当前网址的地址就会发生变化。

      有一点需要注意的是,window.history.length虽然返回是的当前队列的元素个数,但不代表history本身就是那个队列,通过不同浏览器的对history[i]的输出:

   可以看到history是一个数组,它的作用是让用户拿到history.length,当前的长度,但是填充的内容是不确定的。 

      除了使用history之外,还有借助hash的方法,网易新闻就是使用了这样的方法:

   //当前第几页
   var pageIndex = window.location.hash.replace("#page=", "") || ;
   function nextPage(){ 
     makeRequest(pageIndex);
     window.location.hash = "#page=" + pageIndex;
   }
   window.addEventListener("hashchange", function(){
     var page = window.location.hash.replace("#page=", "") || ;
     makeRequest(page);
   });

      关于支持性,参考caniuse网站:history IE10及以上支持,hashchange的支持性较好,IE8及以上都支持。

      虽然hashchange的支持性较好,但是history的优点是可以传数据。对一些复杂的应用可能会有很大的发挥作用,同时history支持back/go操作。

以上本文关于h5的history改善ajax列表请求体验,希望大家喜欢。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

AJAX XMLHttpRequest对象详解

编写轻量ajax组件第三篇实现

Ajax请求中async:false/true的作用分析

以上是基於h5的history改善ajax清單請求體驗的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn