【套件筆記 - JS】頁碼 Pagination.js

更新於 2024/02/18閱讀時間約 30 分鐘

Pagintaion 套件 + Axios API 請求範例

demo

demo


一、官網資源

pagination 官網:https://pagination.js.org/docs/index.html

可由此處下載 css 原始檔客製 https://pagination.js.org/docs/index.html#Theme


二、CDN 安裝

頁碼 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/bootstrap@5.3.2/dist/css/bootstrap.min.css">


三、使用範例

https://codepen.io/annchou_illu/pen/oNmZxmd

以下以政府 API 做為資料來源,搭配 Bootstrap 5 切版

3-1. 目標功能

  1. 頁碼與資料渲染
  2. 簡單篩選功能
  3. 點選至多 3 筆資料

3-2. 示範步驟

  1. 規劃版位
  2. 變數、原始資料宣告、按鈕綁定
  3. 撰寫初始化渲染函式 renderData
    .原始資料請求
    .篩選資料生成
    .頁碼生成
  4. 拆解元件
  5. 加入點選物件功能

3-3. 實作開始

  1. 規劃版位 html
    最主要是先建立好渲染資料和頁碼生成位置,完整 html 可見 codepen
<!-- 被點選物件顯示區 -->
<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>
  1. 基本前置設定
    於 JavaScript 準備 API 路徑來源宣告,以及將 DOM 元素綁定監聽。
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()
});
});
  1. 在準備渲染前,先來了解 Pagination.js 和 jQuery 文件。
    - Pagination.js Asynchronous or JSONP:https://pagination.js.org/index.html
    - Pagination.js ajax:https://pagination.js.org/docs/index.html#ajaxFunction
    - jQuery ajax:https://api.jquery.com/jquery.ajax/
  2. Pagintaion.js docs/commenlyused 第三項提到 ajax 的請求格式如下。並且套件支援以 jQuery ajax 操作 API 來源資料,如果請求成功則使用 success 接收並繼續執行,請求失敗則跳到 error
dataSource: function(done){
$.ajax({
type: 'GET',
url: '/test.json',
success: function(response){
done(response);
}
});
}
  1. 建立初始化 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(); // 一啟動網頁就運行
  1. 儲存 API 請求回傳的原始資料
    使用 console 測試,發現我們需要撈回的資料被放在 data 中的 data 屬性,所以 data.data 是我們所需要的,所以宣告一個變數儲存它。
success: function (data) {
const allData = data.data​ //宣告一個 allData 變數來存放 API 回傳的全部資料
},
  1. 撰寫篩選按鈕動作
    因為我們在 html 中寫了三個按鈕,讓它可以做區域篩選,並且上面已經先宣告了變數 selectedFilter,預設值為「全部」。當 selectedFilter 變數的值已經不是「全部」,則將 filteredData 重新賦值成符合篩選條件的資料。
let filteredData = []; // 真正要被渲染的已篩選資料
selectedFilter !== "全部" // 我們在步驟 2 時宣告過全域,並設定初始值為"全部"
? (filteredData = allData.filter((item) => item.name === selectedFilter))
: (filteredData = allData);
  1. 將按鈕加入點擊監聽,測試上述的 selectedFilter 有沒有因點擊而更改。因為每次點擊按鈕都要重新利用 renderData 函式處理,所以我們在執行函式中再度呼叫 renderData
btnFilter.forEach((btn) => {
btn.addEventListener("click", function () {
selectedFilter = btn.value;
renderData();
});
});
  1. 目前我們的 renderData 函式全部是以下狀態,並且加入 console 測試 selectedFilterfilteredData 值是否有跟著按鈕一起改變。確定成功就可以將 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");
});
}
  1. 計算頁碼與設定
    接著用篩選後的資料計算可以生成幾頁頁碼,以下程式碼可以接在剛才 filteredData console 的下面。回到套件 docs/methods,發現我們可以透過 container.pagination({ ... }) 設定套件呈現細節。以下屬性詳細請參照官網文件。
container.pagination({
dataSource: filteredData, //我們剛才建立的實際渲染資料
//locator: "data", // 資料來源中的屬性,因為上面使用的 filterData 已經是處理過的資料,所以可忽略設定
totalNumber: filteredData.length, //實際資料總數
pageSize: 5, //每頁資料數
showPageNumbers: true,
showPrevious: true,
showNext: true
});
  1. 渲染頁碼與資料
    回到官網文件 docs/dataSourcescontainer 中的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​
}
});
  1. 最後補上執行 renderData,讓網頁一開啟就運行。就完成目標功能的第一二項,已經可以作頁碼切換與按鈕篩選資料了。
function renderData(){...}

renderData();
  1. 拆元件
    因為目前 function renderData 內的程式碼冗長,所以先來做拆分整理。我們剛才在 function renderData 內的程式碼大致可以分為
    .基礎架構
    .資料依據按鈕篩選:需要輸入資料 allData,並生成 filteredData
    .將篩選過的資料計算頁碼:需要輸入這兩筆資料 filteredDatacontainer
    .渲染頁碼與資料:需要輸入資料 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
}
  1. 加入點選功能的 checkbox
    先從渲染 checkbox 開始,修改剛才建立好的 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>`;
});
  1. 為 checkbox 加入辨識值
    每一個 checkbox 都需要被辨識,觀察 $.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>`;
});
  1. 儲存被點選的 checkbox
    完成以上步驟後,我們已經可以點選 checkbox,也可以換頁。但如果回到上一頁,會發現剛才點選的 checkbox 狀態因為換頁資料重新渲染,導致失去被點選狀態。因此我們要紀錄有哪些 checkbox 被點選過,之後才能在渲染時判定每個 checkbox 該呈現什麼狀態。
    步驟 2 中,我們有宣告一個 checkedProjectList 變數用來儲存被點選的 checkbox 清單。現在我們建立一個函式來將資料寫入變數中。判讀被點選的 checkbox data-seq,將 seq 存入。讀取 data-* 的方法使用 checkbox.getAttribute("data-seq"),或 checkbox.dataset.seq 都可以。
    另外特別注意的是,我們從 API 取得回來的 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("、");
})
})
}
  1. 回到 function handlePagination 函式,在 callback 處加入 handleCheckProject(),讓它能夠執行。
function handlePagination(filteredData, container){
...

callback: function (res, pagination) {
...

//處理 checkbox 選擇專案
handleCheckProject();
}
});
}
Demo

Demo

  1. 加入判斷當前 checkbox 是否已被點選,生成樣板
    回到 function renderPagination 函式,在進入 each 之後,執行當前 item.projectSEQ 值是否存在於 checkedProjectList 變數中。includes 會返回 true/falseMDN)。
    checkbox (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
}
  1. 完成後的資料表即使換頁再回上一頁,也能繼續顯示相同 checkbox 勾選狀態了。但還有一些小錯誤,即使 checkbox 取消,或是再次點選都會不斷累積相同 seq 編號在 checkedProjectList 變數中。
  2. 限制選取資料數量
    我們要解決上述的 bug 以及完成最後一個任務:限制最多只能選取 3 筆資料。回到 function handleCheckProject,我們要在這裡根據 checkedProjectList 變數內的資料數量判斷是否還能再繼續點選動作。
    ■ 我們可能有幾種情境及對應執行:
    (1)已達最多選取數 → 禁止用戶點選,但因為 checkbox 沒有 disable 屬性,所以我們只能讓 checked 強制取消
    (2)未達最多選取數 → 加入清單
    (3)清單中已有目前點選的 seq 編號 → 判斷為取消點選,從清單中移除
    (4)清單中沒有目前的 seq 編號 → 加入清單
    ■ 綜合以上情境狀況,我們把要情境總結成
    (1)已達最多選取數,並且清單中不存在此 seq → 取消當前 checkbox 勾選狀態
    (2)未達最多選取數 → 根據清單是否存在 seq,執行加入清單或刪除該值的動作​,
    以上不管是判斷清單中是否存在當前 seq,或是執行刪除,都會需要知道該 seq 在清單中的位置,所以可以使用 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("、");
});
});
}
  1. 完成!


四、結尾

這是我原本發布在六角學院 2023 JS 直播班討論區分享的心得,現移植到部落格存放,謝謝 Paul 提供了改寫優化。

五、資料參考

avatar-img
14會員
20內容數
從藝術領域轉職到前端工程師,喜歡書寫學習歷程和技術文件,掌握經驗與隨時提取的感覺很好。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Ann Chou的沙龍 的其他內容
分享這套功能齊全,視覺超級可愛還有響應式變化,教學文件又很容易閱讀的套件 Evo Calendar。 當初在製作 JS side project 時,想找一個與 VCalendar 視覺相近的套件,但多半都不合意。六角學院指派的 side project 教練也幫我找了另一個純 JS 的範例,也很
不喜歡 HTML 原生的時間選擇器外型嗎?試試看 flatpickr.js 吧! 以下是使用 flatpickr 做簡單的示例,以及 flatpickr 使用注意事項。
我依舊維持著修習 JS 的步伐,但我仍然覺得自己對 JS 的熟悉度不足。在 JS 班開課後,我藉由刷題庫和做 side project 專題,填補了課前的不自信感和知識焦慮。最終我們小組在 2.5 個月內開發了一個訂閱制電商網站的前後台,我也參加了 F2E week1 完賽,獲得銀級徽章
這是我參加為期三個月的六角學院 2023 網頁前端切版直播班中的學習和成長經驗。最初參加直播班時誤以為自己已經具備足夠的前端知識,但後來發現自己的程式碼還有改進的空間。我在參與直播班的過程中,不僅學到了更多切版技術,也在小組協作中體驗到了組織能力和團隊合作的重要性,並從做設計稿與切版中發現個人優勢。
軟工體驗營最後一周,短短一個月的前端程式體驗,真的是非常超值的課程。不論是檢視自己對寫程式的感受,或是透過社群認識自己的新面向、軟實力的培養都是。六角是非常新手友善的程式學校,推薦給每位想學習前端的初心者朋友。
遭受學習挫折的一周,開始發現社群的重要性,最終還是回歸於自己報名體驗營的目的。
分享這套功能齊全,視覺超級可愛還有響應式變化,教學文件又很容易閱讀的套件 Evo Calendar。 當初在製作 JS side project 時,想找一個與 VCalendar 視覺相近的套件,但多半都不合意。六角學院指派的 side project 教練也幫我找了另一個純 JS 的範例,也很
不喜歡 HTML 原生的時間選擇器外型嗎?試試看 flatpickr.js 吧! 以下是使用 flatpickr 做簡單的示例,以及 flatpickr 使用注意事項。
我依舊維持著修習 JS 的步伐,但我仍然覺得自己對 JS 的熟悉度不足。在 JS 班開課後,我藉由刷題庫和做 side project 專題,填補了課前的不自信感和知識焦慮。最終我們小組在 2.5 個月內開發了一個訂閱制電商網站的前後台,我也參加了 F2E week1 完賽,獲得銀級徽章
這是我參加為期三個月的六角學院 2023 網頁前端切版直播班中的學習和成長經驗。最初參加直播班時誤以為自己已經具備足夠的前端知識,但後來發現自己的程式碼還有改進的空間。我在參與直播班的過程中,不僅學到了更多切版技術,也在小組協作中體驗到了組織能力和團隊合作的重要性,並從做設計稿與切版中發現個人優勢。
軟工體驗營最後一周,短短一個月的前端程式體驗,真的是非常超值的課程。不論是檢視自己對寫程式的感受,或是透過社群認識自己的新面向、軟實力的培養都是。六角是非常新手友善的程式學校,推薦給每位想學習前端的初心者朋友。
遭受學習挫折的一周,開始發現社群的重要性,最終還是回歸於自己報名體驗營的目的。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
序列化(serialization)是將資料結構或對象轉換為一個格式,可以被儲存到文件或記憶體中,或者可以透過網路傳輸到另一個系統環境。這使得資料可以在不同的系統之間進行交換,並在需要時重新建構回原始的資料結構。本文將介紹兩個好用的Python套件-JSON與Pickle,並比較兩者的不同。
Thumbnail
最近遇到了一個思考有點久的問題,如何將數值不同的樣品進行分組,同時每組的總和不能超越固定的上限值,且某些樣品不能被分在同一組。雖然規則並不困難,但是人工進行分組卻頗花時間,是不是有可能自動化處理這個步驟?如果有可能的話想要產出多個不同的分組方法,最後由人工選擇最佳的分組方式。
Thumbnail
上一篇文章說明了Pillow套件的基礎操作,這篇文章則會透過四個範例來示範如何利用Pillow製作簡單的GIF動畫。
Thumbnail
一早看著IThome的新聞發現到這個標題「📢 PyPI新帳號現需要啟用雙因素驗證才能執行管理操作」, 而近期幾乎都在接觸Python語言, 在Python的生態圈裡相信對於「pip install…」應該相當熟悉了吧! 但對於背後的平台相信我們不曾仔細去了解一番, 這好藉著這次的觀點也順便來介紹一
Thumbnail
本篇適合: > 剛開始學習 HTML / CSS ,對基本語法有了解的人 > 想要快速建立一個一頁式網站,但對 CSS 仍無法很活用的人 初始設定與 Bootstrap 中文版網頁使用 在過去在大學期間擔任助教的過程,常常有人問「Bootstrap」是什麼?一來我也不是什麼前端工程師,我一時也不太知
如有需要可以不用浪費效能重新將整個頁面重新載入,可以使用非同步的JS,使用動態載入資料
Thumbnail
ANKH原意為生命之鑰,是古埃及藝術用來代表生命的符號。Ankh Numpad延續Aaru的浮雕風格,摘錄了羅塞塔石碑的聖碑體倒數4~5排的部份文字,讓原本單純的Numpad鍵盤賦予更深一層的意涵,若再搭配TKL的Aaru,能讓按鍵功能更加完整,自然不能錯過啦~
Thumbnail
MotoGP油箱上長出翅膀背後的意義是?這都跟最新的空氣動力學提供更多的抓地力有關。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
序列化(serialization)是將資料結構或對象轉換為一個格式,可以被儲存到文件或記憶體中,或者可以透過網路傳輸到另一個系統環境。這使得資料可以在不同的系統之間進行交換,並在需要時重新建構回原始的資料結構。本文將介紹兩個好用的Python套件-JSON與Pickle,並比較兩者的不同。
Thumbnail
最近遇到了一個思考有點久的問題,如何將數值不同的樣品進行分組,同時每組的總和不能超越固定的上限值,且某些樣品不能被分在同一組。雖然規則並不困難,但是人工進行分組卻頗花時間,是不是有可能自動化處理這個步驟?如果有可能的話想要產出多個不同的分組方法,最後由人工選擇最佳的分組方式。
Thumbnail
上一篇文章說明了Pillow套件的基礎操作,這篇文章則會透過四個範例來示範如何利用Pillow製作簡單的GIF動畫。
Thumbnail
一早看著IThome的新聞發現到這個標題「📢 PyPI新帳號現需要啟用雙因素驗證才能執行管理操作」, 而近期幾乎都在接觸Python語言, 在Python的生態圈裡相信對於「pip install…」應該相當熟悉了吧! 但對於背後的平台相信我們不曾仔細去了解一番, 這好藉著這次的觀點也順便來介紹一
Thumbnail
本篇適合: > 剛開始學習 HTML / CSS ,對基本語法有了解的人 > 想要快速建立一個一頁式網站,但對 CSS 仍無法很活用的人 初始設定與 Bootstrap 中文版網頁使用 在過去在大學期間擔任助教的過程,常常有人問「Bootstrap」是什麼?一來我也不是什麼前端工程師,我一時也不太知
如有需要可以不用浪費效能重新將整個頁面重新載入,可以使用非同步的JS,使用動態載入資料
Thumbnail
ANKH原意為生命之鑰,是古埃及藝術用來代表生命的符號。Ankh Numpad延續Aaru的浮雕風格,摘錄了羅塞塔石碑的聖碑體倒數4~5排的部份文字,讓原本單純的Numpad鍵盤賦予更深一層的意涵,若再搭配TKL的Aaru,能讓按鍵功能更加完整,自然不能錯過啦~
Thumbnail
MotoGP油箱上長出翅膀背後的意義是?這都跟最新的空氣動力學提供更多的抓地力有關。