Trang chá»§
Pagination UI
Save
Settings
Sign Up
Log In
Save
Settings
HTML
Copy
<div class="pg"> <ul class="pg-list"> <li class="pg-btn prev"> <svg viewBox="0 0 512 512"> <path d="M22.6 278.6L0 256l22.6-22.6 128-128..." /> </svg> </li> <ul class="pg-num"></ul> <li class="pg-btn next"> <svg viewBox="0 0 512 512"> <path d="M489.4 278.6L512 256l-22.6-22.6-128..." /> </svg> </li> </ul> </div>
CSS
Copy
* { box-sizing: border-box; } ul, li { list-style: none; padding: 0; margin: 0; } a { text-decoration: none; } .pg .pg-list, .pg .pg-num { display: flex; align-items: center; gap: 6px; } .pg .pg-item { user-select: none; min-width: 32px; height: 32px; line-height: 32px; text-align: center; font-size: 16px; border-radius: 50%; transition: color .25s, background-color .25s; color: #363636; } .pg .pg-item:not(.dots):hover { background: rgba(0,0,0,.08); } .pg .pg-item.active { background: #1dc071; } .pg .pg-item.active a { color: #fff; } .pg .pg-item a { display: inline-block; width: 100%; color: #363636; } .pg .pg-btn { cursor: pointer; } .pg .pg-btn.disabled { pointer-events: none; } .pg .pg-btn.disabled svg { color: #a1a1a1; } .pg .pg-btn svg { width: 16px; display: block; margin: auto; color: #363636; }
JS
Copy
const Pagination = ({ totalPage, page = 1, selector, siblingCount = 1, boundaryCount = 1, onSelected }) => { const root = document.querySelector(selector); const numWrap = root?.querySelector('.pg-num'); const btnPrev = root?.querySelector('.pg-btn.prev'); const btnNext = root?.querySelector('.pg-btn.next'); const dots = '<li class="pg-item dots">...</li>'; const createItem = (n, active = false) => `<li class="pg-item${active ? ' active' : ''}"> <a href="#" onclick="event.preventDefault()">${n}</a> </li>`; const setBase = (page, total, before, after) => { let html = ''; for (let i = before; i <= after; i++) { if (i <= 0) i = 1; if (i > total) break; html += createItem(i, page === i); } return html; }; const handleBtn = (page) => { btnPrev.classList.toggle('disabled', page === 1); btnNext.classList.toggle('disabled', page === totalPage); const move = (step) => { const newPage = page + step; render(newPage); onSelected?.(newPage); }; btnPrev.onclick = () => move(-1); btnNext.onclick = () => move(1); }; const render = (page) => { const s = siblingCount, b = boundaryCount > 0 ? boundaryCount : 1; const init = 3, pd = 2; const view = init + s * 2 + b * 2; const dir = pd + s + b; let html = '', before = page - s, after = page + s; let left = b, right = b; const large = totalPage > view; if (large) { if (page <= dir) { left = page - (1 + s); after += dir - page; } if (page + dir > totalPage) { right = totalPage - (page + s); before -= dir - (totalPage - page) - 1; } for (let i = 1; i <= left; i++) html += createItem(i); if (page - dir > 0) html += dots; html += setBase(page, totalPage, before, after); if (totalPage - (page + dir) >= 0) html += dots; for (let i = totalPage - right + 1; i <= totalPage; i++) html += createItem(i); } else { html += setBase(page, totalPage, 1, totalPage); } numWrap.innerHTML = html; numWrap.querySelectorAll('.pg-item:not(.dots)').forEach((el) => { el.onclick = () => { if (el.classList.contains('active')) return; const val = Number(el.textContent); render(val); onSelected?.(val); }; }); handleBtn(page); }; render(page); }; Pagination({ totalPage: 22, page: 1, selector: '.pg', siblingCount: 2, boundaryCount: 1, onSelected: (p) => console.log('Page:', p) });