js之頁面列表載入常用方法總結

2022-09-17 21:04:08

導語:最近由於一些事情需要處理,所以沒來得及寫技術總結了。今天終於可以坐下來好好的梳理一下脈絡,說一下那個在日常前端開發過程中,常用到的頁面列表載入的方法總結。這裡介紹三種方法,分別是分頁載入、按鈕載入以及捲動載入。

目錄

  • 方法簡介
  • 程式碼實現
  • 效果預覽

方法簡介

在日常的前端開發過程中,我們經常會碰到列表很長,不可能完全顯示出來,所以就要進行分頁,每頁固定顯示幾條,然後下面是頁數,點到哪頁顯示哪頁的內容。

除了常見的分頁載入外,還要點選按鈕載入,這種載入方法就是不需要點選下一頁這種了,直接點選按鈕往第一頁的後面補上下一頁的內容,非常方便。

除了以上兩種,捲動載入也是用的比較多的一種列表載入方法,下面就這三種方法做一下總結歸納,方便需要的小夥伴們使用。

封裝實現

下面就對三種方法分別做一下原理解析和方法實現。

下面的列表使用了JSONPlaceholder站點上的一些資料作為列表來源。

分頁載入

當頁面的需求是要顯示一個列表或者表格,總數很多放不下,這時候可以把全部的資料分成多頁,每頁顯示固定的條數,計算出總頁數,然後渲染一下就可以了。

  • 頁面佈局
<div class="wrap">
    <ul id="list"></ul>
    <ul id="pages"></ul>
</div>
.wrap {
    max-width: 960px;
    margin: 0 auto;
    padding: 15px 0;
}

.wrap li {
    padding: 5px 0;
    list-style: square;
}

.wrap li h3,
.wrap li p {
    text-transform: capitalize;
}

.wrap li h3:hover {
    color: #f00;
    cursor: pointer;
}

#pages li {
    display: inline-block;
    margin-right: 10px;
    list-style: none;
}

#pages button {
    width: auto;
    min-width: 40px;
    height: 40px;
    background: #fff;
    box-shadow: 0 0 5px #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    font-size: 16px;
}

#pages button:hover,
#pages button.active {
    color: #fff;
    border-color: #f00;
    background: #f00;
    cursor: pointer;
}

#pages button.dis {
    cursor: no-drop;
}

.wrap .loading {
    line-height: 70vh;
    text-align: center;
    list-style: none;
}

.wrap .nodata {
    list-style: none;
    text-align: center;
}
  • 定義變數
let datas = [], // 分組列表
current = 1, // 當前頁
pages = 0, // 總頁數
total = 0, // 總數
listElem = document.getElementById('list'), // 列表內容
pageElem = document.getElementById('pages'); // 頁數按鈕
  • 處理資料

我們使用axios來獲取json資料,模擬抓取介面的情況。

// 獲取列表
async function getList (page = 1) {
    let res = await axios.get('https://jsonplaceholder.typicode.com/posts');
    if (res.status === 200) {
        let data = sliceData(res.data);
        pages = data.pages;
        total = res.data.length;
        datas = [...data.list];
        return {
            code: 200,
            msg: 'get_succ',
            data: {
                list: data.list[page-1],
                current: page,
                pages: data.pages,
                total: list.length,
            }
        }
    }
}

寫一個切割陣列的方法,分成等份的陣列。

// 處理資料
function sliceData (list) {  
    let newArr = [],step = 10,pages = Math.ceil(list.length/10);
    for (let i = 0; i < list.length; i+=step) {
        let item = list.slice(i, i+step);
        newArr.push(item);
    }
    return {
        list: newArr,
        pages,
    };
}
  • 顯示列表
showList(current);

// 顯示列表
async function showList (current) {
    let data = null;
    listElem.innerHTML = '';
    listElem.innerHTML = '<li class="loading">載入中...</li>';
    if (datas && datas.length) {
        data = {
            code: 200,
            msg: 'get_succ',
            data: {
                list: datas[current-1],
                current: current,
                pages,
                total,
            }
        }
    } else {
        data = await getList(current);
    }
    if (data.code === 200) {
        let list = data.data.list;
        if (list && list.length) {
            let liStr = '',pageStr = '';
            for (const item of list) {
                liStr += `<li>
                    <h3>${item.title}</h3>
                    <p>${item.body}</p>
                </li>`;
            }
            
            setTimeout(() => {
                listElem.innerHTML = liStr;
            }, 1000);

            if (pageElem.innerText === '') {
                for (let i = 0; i < data.data.pages; i++) {
                    pageStr += `<li><button class="page" data-id="${i+1}">${i+1}</button></li>`
                }
                pageElem.innerHTML = `
                <li><button id="start" data-id="1">首頁</button></li>
                <li><button id="prev">上一頁</button></li>
                ${pageStr}
                <li><button id="next">下一頁</button></li>
                <li><button id="end" data-id="${data.data.pages}">尾頁</button></li>`;
                showHighLight(current);
                addClick();
            }
        } else {
            listElem.innerHTML = '<li class="nodata">暫無資料</li>';
        }
    }
}
  • 新增點選事件
// 新增點選
function addClick () {  
    let btns = document.querySelectorAll('#pages li button');
    for (const item of btns) {
        item.addEventListener('click', toggleList, false);
    }
}
  • 切換頁面內容
// 切換頁面
function toggleList (event) {  
    let id = event.target.dataset.id,
    bid = event.target.id;
    if (id) {
        current = Number(id);
    }
    if (bid == 'prev') {
        if (current <= 1) {
            current = 1;
        } else {
            current--;
        }
    } else if (bid == 'next') {
        if (current >= pages) {
            current = pages;
        } else {
            current++;
        }
    }
    showHighLight(current, bid);
    showList(current);
}
  • 顯示高亮
// 顯示高亮
function showHighLight (current, bid) {
    let btns = document.querySelectorAll('.page'),
    startBtn = document.getElementById('start'),
    endBtn = document.getElementById('end');
    for (const item of btns) {
        item.className = 'page';
    }
    btns[current-1].className = 'page active';
    startBtn.className = current == 1 ? 'active dis' : '';
    endBtn.className = current == pages ? 'active dis' : '';
}

其中渲染好頁面後,還加了一個定時器是模擬從伺服器獲取資料等待過程的效果,真實情況下不需要這樣。

按鈕載入

按鈕載入的方法和上面的相似,也就是分頁那塊改成一個按鈕了,不斷在現有的列表中新增新的列表內容,其餘和分頁載入沒有太大區別。

  • 頁面結構
<div class="wrap">
    <ul id="list"></ul>
    <p class="loadmore">載入中...</p>
    <p class="more-box">
        <button id="more">載入更多</button>
    </p>
</div>
  • 頁面美化
.more-box {
    text-align: center;
}

#more {
    padding: 10px;
    background: none;
    border: 1px solid #ccc;
    border-radius: 5px;
}

#more:hover {
    cursor: pointer;
    border-color: #f00;
    background-color: #f00;
    color: #fff;
}

.loadmore {
    text-align: center;
}

.hide {
    display: none;
}
  • 獲取變數
let loadMore = document.querySelector('.loadmore'),
moreBtn = document.getElementById('more');
  • 點選載入更多
// 新增點選
moreBtn.addEventListener('click', addList, false);

// 切換頁面
function addList () {
    if (current < pages) {
        current+=1;
        showList(current);
    } else {
        moreBtn.innerText = '沒有更多了';
    }
}
  • 顯示頁面

在原有的顯示列表方法基礎上修改幾處就好了。

// 顯示列表
async function showList (current) {
    let data = null;
    loadMore.className = 'loadmore';
    if (datas && datas.length) {
        data = {
            code: 200,
            msg: 'get_succ',
            data: {
                list: datas[current-1],
                current: current,
                pages,
                total,
            }
        }
    } else {
        data = await getList(current);
    }
    if (data.code === 200) {
        let list = data.data.list;
        if (list && list.length) {
            let liStr = '',pageStr = '';
            for (const item of list) {
                liStr += `<li>
                    <h3>${item.title}</h3>
                    <p>${item.body}</p>
                </li>`;
            }

            listElem.innerHTML += liStr;

        } else {

            listElem.innerHTML = '<li class="nodata">暫無資料<li>';
        }

        
        setTimeout(() => {
            loadMore.className = 'loadmore hide';
        }, 1000);
    }
}

捲動載入

捲動載入就是在頁面捲動到底部後自動新增新的一頁內容到當前列表後面,每次捲動根據計算動態新增內容。

就是在按鈕載入的基礎上更改而來的,具體的原理是當檔案的到頂部的高度加上檔案的視覺化高度大於檔案的捲動高度的時候就載入頁面。

  • 頁面結構
<div class="wrap">
    <ul id="list"></ul>
    <p class="loadmore">載入中...</p>
</div>
  • 捲動判斷
document.addEventListener('scroll', checkScroll, false);
function checkScroll () {  
    let scrollTop = document.documentElement.scrollTop,
    clientHei = document.documentElement.clientHeight,
    scrollHeight = document.documentElement.scrollHeight;
    if (scrollTop + clientHei >= scrollHeight) {
        addList();
    }
}

// 切換頁面
function addList () {
    if (current < pages) {
        current+=1;
        showList(current);
    } else {
        loadMore.innerText = '沒有更多了';
    }
}

效果預覽

  • 分頁載入

線上預覽

  • 按鈕載入

線上預覽

  • 捲動載入


線上預覽

最後的話

以上就是我在日常開發過程中的用的幾種載入的方法,如果有什麼問題,歡迎郵箱聯絡我。