Pagintaion 套件 + Axios API 請求範例
pagination 官網:https://pagination.js.org/docs/index.html
可由此處下載 css 原始檔客製 https://pagination.js.org/docs/index.html#Theme
頁碼 pagination.scss(非必要引入,也可以從官網下載原始檔更改)
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paginationjs/2.6.0/pagination.min.css">
jQuery Import(使用 slim.min.js 版本會出錯)
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
頁碼 pagination.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/paginationjs/2.6.0/pagination.min.js"></script>
Bootstrap 5 CSS(建立表格用,非必要)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
https://codepen.io/annchou_illu/pen/oNmZxmd
以下以政府 API 做為資料來源,搭配 Bootstrap 5 切版
html
<!-- 被點選物件顯示區 -->
<p class="bg-light">你選擇的專案 seq:<span class="showCheckedList"></span></p>
<!-- 篩選按鈕區 -->
<div class="d-flex justify-content-end gap-1 mb-3">
<input type="button" class="btn btn-secondary btnFilter" value="全部" />
<input type="button" class="btn btn-secondary btnFilter" value="前鎮區" />
<input type="button" class="btn btn-secondary btnFilter" value="三民區" />
</div>
<!-- 資料生成位置與內容模板 -->
<div id="pagination-Container">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between">
<div>
<p>專案名稱</p>
<p>專案區域</p>
</div>
<input class="form-check-input" type="checkbox" id="checkProject" />
</li>
</ul>
</div>
<!-- 頁碼 -->
<div id="pagination-Pages" class="d-flex justify-content-end mt-3"></div>
const _url =
"https://api.kcg.gov.tw:443/api/service/Get/1f2a6afe-f953-436f-981c-92f2739b3475";
// 顯示選取專案
const showCheckedList = document.querySelector(".showCheckedList");
const checkedProjectList = []; // 被選取清單
// 初始篩選分類
let selectedFilter = "全部";
// 按鈕篩選處理
const btnFilter = document.querySelectorAll(".btnFilter");
// 按鈕監聽
btnFilter.forEach((btn) => {
btn.addEventListener("click", function () {
selectedFilter = btn.value; // 當按鈕按下,selectedFilter 的值會被改變
renderData(); // 每次被按下都會一再觸發 renderData()
});
});
success
接收並繼續執行,請求失敗則跳到 error
。dataSource: function(done){
$.ajax({
type: 'GET',
url: '/test.json',
success: function(response){
done(response);
}
});
}
function renderData
基本架構function renderData() {
$(function () {
(function (name) {
let container = $("#pagination-" + name); // 這裡面包裝了套件所需設定,暫時不用理會
$.ajax({
url: _url, // 資料來源 API 網址
success: function (data) {
... // 請求成功後執行
},
error: function (error) {
console.error(error); // 請求失敗時執行
}
});
})("Pages");
});
}
renderData(); // 一啟動網頁就運行
console
測試,發現我們需要撈回的資料被放在 data 中的 data 屬性,所以 data.data
是我們所需要的,所以宣告一個變數儲存它。success: function (data) {
const allData = data.data //宣告一個 allData 變數來存放 API 回傳的全部資料
},
selectedFilter
,預設值為「全部」。當 selectedFilter
變數的值已經不是「全部」,則將 filteredData
重新賦值成符合篩選條件的資料。let filteredData = []; // 真正要被渲染的已篩選資料
selectedFilter !== "全部" // 我們在步驟 2 時宣告過全域,並設定初始值為"全部"
? (filteredData = allData.filter((item) => item.name === selectedFilter))
: (filteredData = allData);
renderData
函式處理,所以我們在執行函式中再度呼叫 renderData
。btnFilter.forEach((btn) => {
btn.addEventListener("click", function () {
selectedFilter = btn.value;
renderData();
});
});
console
測試 selectedFilter
和 filteredData
值是否有跟著按鈕一起改變。確定成功就可以將 console
刪除。function renderData() {
$(function () {
(function (name) {
let container = $("#pagination-" + name); // 這裡面包裝了套件所需設定,暫時不用理會
$.ajax({
url: _url, // 資料來源 API 網址
success: function (data) {
const allData = data.data // 宣告一個 allData 變數來存放 API 回傳的全部資料
let filteredData = []; // 真正要被渲染的已篩選資料
selectedFilter !== "全部"
? (filteredData = allData.filter((item) => item.name === selectedFilter))
: (filteredData = allData);
console.log(selectedFilter)
console.log(filteredData)
},
error: function (error) {
console.error(error); // 請求失敗時執行
}
});
})("Pages");
});
}
filteredData console
的下面。回到套件 docs/methods,發現我們可以透過 container.pagination({ ... })
設定套件呈現細節。以下屬性詳細請參照官網文件。container.pagination({
dataSource: filteredData, //我們剛才建立的實際渲染資料
//locator: "data", // 資料來源中的屬性,因為上面使用的 filterData 已經是處理過的資料,所以可忽略設定
totalNumber: filteredData.length, //實際資料總數
pageSize: 5, //每頁資料數
showPageNumbers: true,
showPrevious: true,
showNext: true
});
container
中的callback
屬性可用於插入自訂的 html
,所以我們可以將上面 html
要渲染的資料 html
模板貼下來。input
中的各項屬性視原始資料內容加上獨特值。container.pagination({
//...略
//頁碼渲染與監聽
callback: function (res, pagination) {
let dataHtml = '<ul class="list-group">';
$.each(res, function (index, item) {
dataHtml += `<li class="list-group-item d-flex justify-content-between">
<div>
<p>${item.projectName}</p>
<p>${item.name}</p>
</div>
</li>`;
});
dataHtml += "</ul>";
$("#pagination-Container").html(dataHtml); // 設定 HTML 內容到 container
}
});
renderData
,讓網頁一開啟就運行。就完成目標功能的第一二項,已經可以作頁碼切換與按鈕篩選資料了。function renderData(){...略}
renderData();
function renderData
內的程式碼冗長,所以先來做拆分整理。我們剛才在 function
renderData
內的程式碼大致可以分為allData
,並生成 filteredData
。filteredData
、container
。res
。// 基礎架構
function renderData() {
$(function () {
(function (name) {
let container = $("#pagination-" + name);
$.ajax({
url: _url,
success: function (data) {
// 將完整資料交給 handleFilterData 函式篩選
const allData = data.data
const filteredData = filterData(allData);
// 將返回的 filteredData 計算頁碼
handlePagination(filteredData, container);
},
error: function (error) {
console.error(error);
}
});
})("Pages");
});
}
// 資料依據按鈕篩選:需要輸入資料 allData,並生成 filteredData。
function filterData(data) {
let filteredData = [];
selectedFilter !== "全部"
? (filteredData = data.filter((item) => item.name === selectedFilter))
: (filteredData = data);
return filteredData;
}
//使用篩選資料,計算頁碼
function handlePagination(filteredData, container) { container.pagination({
dataSource: filteredData, // 實際資料來源
//locator: "data", // 資料來源中的屬性,因為上面使用的 filterData 已經是處理過的資料,所以可忽略設定
totalNumber: filteredData.length, // 實際資料總數
pageSize: 5, // 每頁資料數
showPageNumbers: true,
showPrevious: true,
showNext: true,
// 頁碼渲染與監聽
callback: function (res, pagination) {
//渲染頁碼與資料
renderPagination(res); }
});}
// 渲染頁碼與資料
function renderPagination(res) {
let dataHtml = '<ul class="list-group">';
$.each(res, function (index, item) {
dataHtml += `<li class="list-group-item d-flex justify-content-between">
<div>
<p>${item.projectName}</p>
<p>${item.name}</p>
</div>
</li>`;
});
dataHtml += "</ul>";
$("#pagination-Container").html(dataHtml); // 設定 HTML 內容到 container
}
function renderPagination
中的 dataHtml
。$.each(res, function (index, item) {
dataHtml += `<li class="list-group-item d-flex justify-content-between">
<div>
<p>${item.projectName}</p>
<p>${item.name}</p>
</div>
<input class="form-check-input" type="checkbox">
</li>`;
});
$.each(res, function (index, item)
中的 item
可以發現 item.projectSEQ
這個唯一值可以被使用,所以我們可藉由 data-*
(MDN) 的方式加入此值。$.each(res, function (index, item) {
dataHtml += `<li class="list-group-item d-flex justify-content-between">
<div>
<p>${item.projectName}</p>
<p>${item.name}</p>
</div>
<input class="form-check-input" type="checkbox"
id="checkProject${item.projectSEQ}"
data-seq=${item.projectSEQ}> //這裡加入 data-seq
</li>`;
});
checkedProjectList
變數用來儲存被點選的 checkbox 清單。現在我們建立一個函式來將資料寫入變數中。判讀被點選的 checkbox data-seq
,將 seq
存入。讀取 data-* 的方法使用 checkbox.getAttribute("data-seq")
,或 checkbox.dataset.seq
都可以。projectSEQ
參數是 number
型別,所以我們在這裡存入checkedProjectList
變數的值也必須轉成 number
型別才不會之後影響判斷。function handleCheckProject() {
// 將所有 checkbox 綁定
const checkBoxes = document.querySelectorAll("input[type='checkbox']");
// 因為 checkBoxes 有多個 checkbox,所以必須先使用 forEach 才能 addEventListener 監聽
checkBoxes.forEach(checkbox => {
checkbox.addEventListener("change", () => {
const projectSeq = checkbox.getAttribute("data-seq");
checkedProjectList.push(+projectSeq) // 使用「+」轉 number
//因為步驟 2 中已經有做 DOM 綁定,所以在這裡將儲存的資料渲染
showCheckedList.textContent = checkedProjectList.join("、");
})
})
}
function handlePagination
函式,在 callback 處加入 handleCheckProject()
,讓它能夠執行。function handlePagination(filteredData, container){
...略
callback: function (res, pagination) {
...略
//處理 checkbox 選擇專案
handleCheckProject();
}
});
}
function renderPagination
函式,在進入 each
之後,執行當前 item.projectSEQ
值是否存在於 checkedProjectList
變數中。includes
會返回 true/false
(MDN)。checked
在 HTML 中標示,所以也在 dataHTML
中使用三元運算子根據剛才 isChecked
的結果判斷是否加入 checked
。function renderPagination(res) {
let dataHtml = '<ul class="list-group">';
$.each(res, function (index, item) {
// 是否已經被選取
const isChecked = checkedProjectList.includes(item.projectSEQ);
dataHtml += `<li class="list-group-item d-flex justify-content-between"><div><p>${
item.projectName
}</p><p>${
item.name
}</p></div><input class="form-check-input" type="checkbox" id="checkProject${
item.projectSEQ
}" data-seq=${item.projectSEQ}
${isChecked ? "checked" : ""}> // 三元運算子判斷當前 checkbox 狀態
</li>`;
});
dataHtml += "</ul>";
$("#pagination-Container").html(dataHtml); // 設定 HTML 內容到 container
}
checkedProjectList
變數中。function handleCheckProject
,我們要在這裡根據 checkedProjectList
變數內的資料數量判斷是否還能再繼續點選動作。indexOf
尋找。function handleCheckProject() {
const checkBoxes = document.querySelectorAll("input[type='checkbox']");
const maxChecked = 3; // 最多選取數
checkBoxes.forEach((checkbox) => {
checkbox.addEventListener("change", () => {
const projectSeq = checkbox.getAttribute("data-seq");
// 判斷目前的 seq 在 checkedProjectList 中的 index,若無則返回 -1
const findCheckBoxIndex = checkedProjectList.indexOf(+projectSeq);
// 如果已達最多選取數,並且清單中不存在此 seq
if (
checkedProjectList.length === maxChecked &&
findCheckBoxIndex === -1
) {
checkbox.checked = false;
} else {
// 未達最多選取數
findCheckBoxIndex === -1
? checkedProjectList.push(+projectSeq)
: checkedProjectList.splice(findCheckBoxIndex, 1);
}
//渲染選取專案
showCheckedList.textContent = checkedProjectList.join("、");
});
});
}
這是我原本發布在六角學院 2023 JS 直播班討論區分享的心得,現移植到部落格存放,謝謝 Paul 提供了改寫優化。