博客 / 詳情

返回

手摸手教你實現移動端滾動記憶(帶分頁)

前戲:

在移動端網頁中的列表如何實現滾動和搜索條件的記憶,類似微信文章一樣,瀏覽到文章的某一個位置,在下次打開的時候依然能滾動到上次瀏覽的位置繼續瀏覽。本篇文章介紹的是帶分頁的列表,如果你現在需求是不帶分頁的文章或列表當然也可以參考,實現方式基本是差不多的。

因為這裏使用了mui的下拉刷新的列表組件,要在tab切換時需要默認把滾動條重置到最頂部(從頭開始瀏覽),refreshContainer為對應列表id
mui列表組件相關的代碼可以參考我之前的文章:
【mui 多個tab頁實現下拉刷新上拉加載】https://segmentfault.com/a/11...

mui("#refreshContainer").scroll().scrollTo(0, 0, 0);//tab切換時默認滾到頂部

在頁面加載完成時定義一些工具函數:
localGet就是localStorage.getItem的一個簡單封裝

  if (localGet("woAppInfo") == null){//首次加載讀取上一次的查詢條件
     saveWoAppInfo({
       tabId: "untreated",
       scrollTop: 0,
     });
     }

/**
 * 防抖函數
 * @param {需要防抖的函數} func
 * @param {防抖時間段} delay
 */
function debounce(fn, wait) {
  var timer = null;
  return function () {
    if (timer !== null) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn.bind(this), wait);
  };
}
function saveWoAppInfo(woappInfo){
    localStorage.setItem("woAppInfo", JSON.stringify(woappInfo));
}

當列表數據渲染完成時執行autoScrollTo滾動到上次位置

function autoScrollTo() {
  setTimeout(function () {
    var scrollTop1 =
      localGet("woAppInfo") && JSON.parse(localGet("woAppInfo")).scrollTop;
    
    // mui("#refreshContainer").scroll().scrollTo(0, -1000, 0);
    // $("#refreshContainer").scrollTop(scrollTop);
      
    mui("#refreshContainer").pullRefresh().scrollTo(0, scrollTop1, 0);
  }, 500);
}

注意點:

列表分頁的代碼邏輯因為不是文章主要內容就在這裏就不給大家説明了,大致邏輯是用户滾動到底部(最後一條記錄)->觸發mui列表的上拉回調函數->通過當前分頁數據對下一頁數據繼續進行獲取->append到列表後面實現分頁

queryObj對象是在搜索和tab切換的的時候把搜索條件以key-value的形式存到裏面,當在下次頁面打開時就默認使用AppInfo中的搜索條件達到搜索條件記憶的效果。
scroll.y為當前滾動條距離到頁面列表頂部的高度數值,因為在頂部往上拉時滾動條超出頂部就有可能是負數所以需要使用絕對值Math.abs
滾動事件初始化(autoScrollInit)這裏也要給組件的默認滾動到上次位置:

function autoScrollInit() {
     
  var scroll = mui("#refreshContainer").scroll({
    scrollY: true, //是否豎向滾動
    scrollX: false, //是否橫向滾動
    startY:
      localGet("woAppInfo") && JSON.parse(localGet("woAppInfo")).scrollTop,
    indicators: false,
  });

  document.querySelector("#refreshContainer").addEventListener(
    "scroll",
    debounce(function () {
      var href = $(".A-tab span.active").attr("href");
      var queryObj = JSON.parse(localGet("woAppInfo")).queryObj || {};
      var pageSize = pages[href].pageSize;
      var listItemHeight = 110;//列表中單條記錄的高度
      queryObj.pageCount =
        Math.floor(Math.abs(scroll.y) / (pageSize * listItemHeight) + 1) *
        pageSize; //每頁數量 = 當前下拉的距離長度/(一頁的長度) * pageSize
      saveWoAppInfo({
        tabId: href,
        queryObj: queryObj,
        scrollTop: Number(scroll.y.toFixed()),
      });
    }, 1000)
  );
}

var woAppInfo = localGet("woAppInfo") && JSON.parse(localGet("woAppInfo"));
var tabId = woAppInfo.tabId;
//自動選擇上一次的頂部tab頁
if (tabId){
  $('span[href="' + tabId + '"]').addClass("active");
  $(".list[id='" + tabId + "']").addClass("active");
}else{
    $('span[href="untreated"]').addClass("active");
    $(".list[id='untreated']").addClass("active");
}   

分頁滾動記憶原理:

listItemHeight為單條記錄的高度,可以自己根據單條記錄的高度來設定,有了這個高度然後通過當前列表中的滾動條y軸位置到頂部數值計算出滾動條到第一條記錄的列表條數(pagecount) Math.floor(Math.abs(scroll.y) / (pageSize * listItemHeight) + 1) * pageSize;
這樣做的原因是我們列表是分頁加載的數據,所以為了下次能夠滾到記憶的位置所以這裏要計算一下記憶需要的記錄條數和搜索條件,然後保存到 AppInfo中,在下次獲取數據時通過pageCount每頁數量去請求數據直接就能還原出上次的數據量這樣才能和scroll.y的位置匹配得上。(因為如果上次滾動條位置是幾百條的y軸位置,但這次記憶滾動的時候卻才加載了幾條數據,所以就導致因為數據不足自然就沒辦法滾動到幾百條的位置)
在列表數據請求時(搜索或者初始加載),如果是普通的初始進入的加載才進行記憶,在列表渲染完成後首先初始化監聽列表的滾動事件,然後再還原上次滾動條的位置(autoScrollTo直接自動滾動到對應位置),並在滾動時取出當前的搜索條件和tab的id用於保存,注意這裏為了性能問題需要設置防抖,抖到1s後再保存數據

執行saveWoAppInfo後的AppInfo存儲情況:

image.png

以下是列表請求的代碼:


var woAppInfo =
 localGet("woAppInfo") && JSON.parse(localGet("woAppInfo"));
 if (woAppInfo.queryObj && woAppInfo.queryObj.pageCount) {
   data.data.pageCount = woAppInfo.queryObj.pageCount;
 }

  ajax(data, {
    success: function (json) {
         var woAppInfo =
           localGet("woAppInfo") && JSON.parse(localGet("woAppInfo"));
               if (data.data.isSearch) {
                //當攜帶查詢條件時默認滾到頂部
                 mui("#refreshContainer").scroll().scrollTo(0, 0, 0);
                 mui("#refreshContainer").pullRefresh().scrollTo(0, 0, 0);
               }
            if (
              data.data.isSearch == undefined &&
              woAppInfo.tabId === data.data.href
            ) {//當首次進入時對當前tab進行滾動記憶
                  autoScrollInit();
                  autoScrollTo();
            }
       
    },
    fail: function (json) {
    ...
    },
    error: function (e) {
  ...
    },
  });

當列表觸發下拉刷新回調時重新清除搜索條件(因為相當於重新加載列表 不算上條件了),並保存當前tabid:

//清空查詢參數
function clearSearchParams() {
  cacheObj = {
    //存儲搜索時的搜索條件
    xxxx: "",
    aaa: "",
    id: href === "all" ? user.id : "",
  };
 saveWoAppInfo({ tabId: href, scrollTop: 0 });
}

    function pulldownRefresh() {

     var href = $(".A-tab span.active").attr("href");

      clearSearchParams(href);
    fetchData(function () {//加載列表
      mui("#refreshContainer").pullRefresh().endPulldownToRefresh();
    });
  }

總結:

本篇主要説明了移動端h5中的分頁列表如何進行滾動的記憶
簡單來説就是通過瀏覽器的Scroll事件對列表滾動條的y軸位置保存到localStorage中,在下次加載再通過自動滾動的方法滾動到上次位置,但是注意要通過計算還原出上次所記憶的數據量,因為需要足夠的y軸空間去滾動。
如果覺得好的話希望大家給個贊~ 非常感謝

【手摸手教你實現頁面tab和導航菜單記憶功能】https://segmentfault.com/a/11...

user avatar hightopo 頭像 79px 頭像 clearlove07 頭像 mouyi_63f6f68ba66d9 頭像 ran_agppr 頭像 kandole 頭像 liyuan_5aa3282cf3353 頭像 yangzw 頭像
8 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.