页码导航需JavaScript控制数据切片与DOM更新,配合语义化HTML(如<nav aria-label="Pagination"><ol>)和CSS,确保无障碍、可打印及URL同步。
HTML 模板里加页码导航,不是加个标签就能用——必须靠 JavaScript 控制数据切片 + DOM 更新,再配语义化 HTML 结构和基础 CSS 样式。纯静态 HTML 无法自动翻页、无法响应点击、也无法同步 URL。
别用 <div class="pagination"> 包一堆数字。浏览器和读屏软件认的是语义,不是样式。
<nav aria-label="Pagination"> 是必需外层容器,否则键盘用户无法跳过整组页码<ol>(不是 <ul>),因为页码是有序序列,<ol> 天然支持计数器且语义准确aria-current="page",不能只靠 class="active" —— 否则屏幕阅读器读不出“这是第 3 页”… 必须是真实文本节点,写成 <li>…</li>,不能用伪元素或 SVG 替代<a> 或带 role="link" 的 <button>,禁用时要移除 href 并设 aria-disabled="true"
常见错误是每次点页码都重新 fetch 全量数据,或没防抖导致连点触发多次请求。核心是把「页码变更」和「数据加载」解耦。
URLSearchParams 读写查询参数:const page = parseInt(new URLSearchParams(location.search).get('page')) || 1,别手动解析 location.search 字符串document.querySelector('.pagination').addEventListener('click', e => { if (e.target.matches('a[data-page]')) { ... } }),避免为每个 <a> 单独绑事件e.preventDefault(),否则页面会滚到顶部;更新 URL 用 history.pushState() + location.replace() 组合,保证后退可用page 和 size 参数;前端分页则用 Array.prototype.slice() 截取,注意边界检查:data.slice((page - 1) * size, page * size)
aria-disabled="true",最后一页时下一页同理;DOM 上同时移除 href,仅靠 CSS 灰色不可靠你在页面里写的 <div class="page-number">第 2 页</div>,打印预览里根本不会出现在每张物理页右下角——因为浏览器打印页码是 UI 层功能,和 DOM 完全隔离。
立即学习“前端免费学习笔记(深入)”;
document.querySelectorAll('p, h2, table') 累计 getBoundingClientRect().height,超限时插入 <section class="print-page">
break-before: always 强制分页,再用 position: absolute 把页码文本钉在每块底部@page { @bottom-center { content: "第 " counter(page) " 页"; } } 在 Chrome 中基本不可用,Firefox 支持有限且无法控制起始值,别押注它document.fonts.load() 等字体就绪后再执行切页逻辑当列表项超过 500 条,直接 innerHTML = '' 拼接再赋值,会触发多次重排,滚动和点击明显延迟。
innerHTML += 循环拼接页码按钮,每次赋值都重解析 DOMdocument.createDocumentFragment() 离屏构建完整页码 <ol>,最后一次性 appendChild()
margin-left: calc(var(--level) * 1.5em),别用 JS 动态设 style.marginLeft
<li> 单独绑 addEventListener,内存占用低且移除方便scrollIntoView({ behavior: 'smooth' }) 支持不稳定,降级方案是 behavior: 'auto' 或用 window.scrollTo() 手动算位置真正难的不是生成“1 2 3 … 下一页”,而是让页码状态、URL、DOM 渲染、无障碍属性、打印行为全部对齐。任何一个环节断开,用户就会卡在某一页回不去,或者屏幕阅读器念不出当前页,又或者打印出来全是空白页。