前言
在日常的前端开发中,分页器是一个非常常见的组件。虽然 Bootstrap 提供了默认的分页器组件,但是在某些应用场景中,我们往往需要更加个性化的分页器组件,以符合业务需要。本文将介绍如何使用 Custom Elements 和 Bootstrap,创建一个高度自定义的分页器组件,以及相关的技术细节和实现方案。
准备工作
在开始编写自定义分页器组件之前,需要准备以下几个工具和技术:
在本文中,我们将使用 Bootstrap 4 来构建分页器的样式,同时使用 Custom Elements 来实现分页器的自定义组件。
分页器组件的基本结构
在开始编写组件之前,首先需要明确分页器组件的基本结构。一个基本的分页器组件应该包含以下几个部分:
- 上一页按钮
- 下一页按钮
- 当前页码的输入框
- 跳转到指定页码的按钮
下面是一个简单的示意图:
在分页器组件中,我们需要提供以下一些属性:
page
:表示当前页码,需要和输入框中的值进行同步。pageSize
:表示每页展示的数据条数。total
:表示数据总条数。showQuickJumper
:是否展示跳转输入框和按钮。
编写分页器组件
1. 创建 Custom Element
首先,我们需要创建一个 Custom Element,用于代表分页器组件。我们给这个元素定义一个 pagination-element
的标签名:
<template id="pagination-template"> <div class="pagination"> <!-- 分页器组件的具体结构 --> </div> </template> <script> class PaginationElement extends HTMLElement { constructor() { super(); const template = document.getElementById('pagination-template').content; this.shadow = this.attachShadow({ mode: 'open' }) .appendChild(template.cloneNode(true)); } } customElements.define('pagination-element', PaginationElement); </script>
在以上代码中,我们使用了 attachShadow
方法来创建了一个 Shadow DOM,将模板插入到其中。接下来我们就可以在模板中编写分页器组件的具体结构了。
2. 编写分页器的基本结构
在模板中,我们可以结合 Bootstrap 4 的样式,编写一个最基本的分页器结构:
<!-- 分页器组件的具体结构 --> <style> .pagination { display: flex; justify-content: center; align-items: center; margin: 20px 0; } .page-item { display: inline-block; padding: 0 10px; font-size: 14px; line-height: 1.5; border: 1px solid #dee2e6; border-radius: 2px; color: #666; } .page-item.active { color: #fff; background-color: #007bff; border-color: #007bff; cursor: default; } .page-item.disabled { color: #999; background-color: #fff; border-color: #dee2e6; cursor: not-allowed; } </style> <div class="pagination"> <ul class="pagination"> <li class="page-item"> <a class="page-link" href="#">上一页</a> </li> <li class="page-item active"> <a class="page-link" href="#">1</a> </li> <li class="page-item"> <a class="page-link" href="#">2</a> </li> <li class="page-item"> <a class="page-link" href="#">3</a> </li> <li class="page-item disabled"> <a class="page-link" href="#">...</a> </li> <li class="page-item"> <a class="page-link" href="#">5</a> </li> <li class="page-item"> <a class="page-link" href="#">下一页</a> </li> </ul> </div>
以上分页器结构包含了分页器的基本元素,即上一页、下一页按钮,以及页码列表。注意,在列表中,我们添加了一个 ...
的占位符,方便展示更多的页码。
3. 实现分页器组件的功能
有了基本的结构之后,接下来我们需要对这个分页器组件进行功能实现。具体来说,我们需要添加以下一些功能:
- 上一页和下一页功能
- 页码列表渲染
- 当前页码输入框和跳转功能
上一页和下一页功能
<li class="page-item"> <a class="page-link" href="#" id="prev">上一页</a> </li> <li class="page-item"> <a class="page-link" href="#" id="next">下一页</a> </li>
通过给上一页和下一页的按钮添加一个 id
值,我们可以方便地通过 JavaScript 获取这个节点,然后给这个节点添加一个点击事件。
constructor() { super(); const template = document.getElementById('pagination-template').content; this.shadow = this.attachShadow({ mode: 'open' }) .appendChild(template.cloneNode(true)); // 绑定上一页和下一页按钮的点击事件 this.shadow.getElementById('prev') .addEventListener('click', this.prevPage.bind(this)); this.shadow.getElementById('next') .addEventListener('click', this.nextPage.bind(this)); } prevPage() { // 上一页逻辑 } nextPage() { // 下一页逻辑 }
接下来,我们还需要给每一个 page-item
添加一个点击事件,方便用户进行手动跳转:
<li class="page-item" id="page-item-1"> <a class="page-link" href="#">1</a> </li> <li class="page-item" id="page-item-2"> <a class="page-link" href="#">2</a> </li> <li class="page-item" id="page-item-3"> <a class="page-link" href="#">3</a> </li>
同样的,我们给每一个 page-item
添加一个 id
来获取节点,然后绑定点击事件即可。
constructor() { // ... // 绑定页码列表的点击事件 const pageItems = this.shadow.querySelectorAll('.page-item'); pageItems.forEach((item) => { item.addEventListener('click', this.gotoPage.bind(this, parseInt(item.id.slice(-1)))); }); } gotoPage(pageNumber) { // 跳转到指定页码 }
页码列表渲染
接下来我们需要实现渲染页码列表的逻辑。
首先,我们需要获取当前分页器的属性值,包括 page
、total
和 pageSize
。
get page() { return parseInt(this.getAttribute('page')) || 1; } set page(val) { this.setAttribute('page', val); } get total() { return parseInt(this.getAttribute('total')) || 0; } set total(val) { this.setAttribute('total', val); } get pageSize() { return parseInt(this.getAttribute('page-size')) || 10; } set pageSize(val) { this.setAttribute('page-size', val); }
接下来,我们可以根据属性值计算出总页数和页面列表。
get totalPages() { return Math.ceil(this.total / this.pageSize); } get pages() { let startPage = 1; let endPage = this.totalPages; if (this.totalPages > 5) { if (this.page <= 3) { endPage = 5; } else if (this.page > this.totalPages - 3) { startPage = this.totalPages - 4; } else { startPage = this.page - 2; endPage = this.page + 2; } } const pages = Array.from(Array(endPage + 1 - startPage).keys()) .map(i => startPage + i); return pages; }
其中,我们通过计算当前页码,然后判断页码列表的起始页码和结束页码。
最后,我们可以通过遍历计算得到的页面列表,来渲染分页器的页码列表。
render() { const pageItems = this.shadow.querySelectorAll('.page-item'); pageItems.forEach((item) => { item.parentNode.removeChild(item); }); const ul = this.shadow.querySelector('ul'); if (this.total < this.pageSize) { for (let i = 1; i <= this.total; i++) { const li = this.generatePageItem(i); ul.insertBefore(li, ul.lastChild); } } else { const pages = this.pages; pages.forEach((page) => { const li = this.generatePageItem(page); ul.insertBefore(li, ul.lastChild); }); } } generatePageItem(num) { const li = document.createElement('li'); li.classList.add('page-item'); li.setAttribute('id', `page-item-${num}`); const a = document.createElement('a'); a.classList.add('page-link'); a.setAttribute('href', `#${num}`); a.innerText = num; li.appendChild(a); if (num === this.page) { li.classList.add('active'); } return li; }
以上代码中,我们通过 generatePageItem
方法来生成每一个页码元素,然后使用遍历,将每个页码元素添加到分页器中。
当前页码输入框和跳转功能
最后,我们需要添加一个输入框和跳转按钮,方便用户手动输入页码进行跳转。
<div class="input-group input-group-sm" id="jump-input" style="display: none;"> <input type="text" class="form-control"> <div class="input-group-append"> <button class="btn btn-outline-secondary" type="button" id="jump-btn">Go</button> </div> </div>
以上代码中,我们使用了 Bootstrap 4 的样式来渲染输入框和按钮,并且给输入框和按钮都添加了一个 id
值来方便获取节点。
接下来,我们绑定跳转按钮的点击事件:
constructor() { // ... this.shadow.getElementById('jump-btn') .addEventListener('click', this.jumpPage.bind(this)); } jumpPage() { const inputValue = parseInt(this.shadow.querySelector('#jump-input input').value); if (!inputValue || inputValue < 1 || inputValue > this.totalPages) { return; } this.page = inputValue; this.render(); }
以上代码中,我们获取到输入框中的值,如果输入值不符合要求则不进行跳转。否则,我们通过设置 page
属性值,然后重新渲染分页器来实现跳转功能。
同时,我们还需要根据 showQuickJumper
属性值,来决定是否展示输入框和按钮:
get showQuickJumper() { return this.hasAttribute('show-quick-jumper'); } set showQuickJumper(val) { if (val) { this.setAttribute('show-quick-jumper', ''); } else if (this.hasAttribute('show-quick-jumper')) { this.removeAttribute('show-quick-jumper'); } } connectedCallback() { if (this.showQuickJumper) { this.shadow.querySelector('#jump-input').style.display = 'block'; } } attributeChangedCallback(name, oldValue, newValue) { if (name === 'show-quick-jumper') { this.shadow.querySelector('#jump-input').style.display = newValue ? 'block' : 'none'; } }
总结
通过使用 Custom Elements 和 Bootstrap,我们可以快速实现一个高度自定义的分页器组件。在组件的实现过程中,我们学习了如何创建一个 Custom Element,
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b4e905add4f0e0ffdc16b8