代码使用class组件编写
下图为最终基本样式,文章最后有组件使用预览GIf图,UI及配色参照了antd的Pagination组件
先确定分页组件需要接受什么Props
组件的完善程度及需求实现全看个人,下面的props及state定义是根据个人需求确定的,仅供参考
class Pagecomponent extends Component {
static defaultProps = {
preBtnText: "<", //上一页的文本
nextBtnText: ">", //下一页的文本
onPageChange: (currentPage) => {}, //页码跳转回调
showQuickJumper: true, //是否展示快速跳转输入框
showTotal: true, //是否展示总条数
};
//...
}
以及确定需要组件自身管理的state,总分页数由传入的total/10后向上取整
constructor(props) {
super(props);
this.state = {
total: props.total || 1, //总条数
totalPageSize: Math.ceil(props.total / 10) || 1, //总分页数
currentPage: props.currentPage || 1, //当前分页数
inputValue: "", //快速跳转输入框值
};
}
渲染出分页组件的主要元素
主要实现逻辑:
- 总分页数<=9条时全部展示,直接渲染出全部页码即可。当总页数>9条时,必定出现省略项...,只是位置有所区别,点击省略项功能参考antd的,默认(+/-)5个页码。
- 当前页数减去4(4为单边最多出现的兄弟项数量)<=1时,渲染1-7的连号页码,尾巴渲染省略...项及总分页数。
- 当前页数加上4(4为单边最多出现的兄弟项数量)>=总页数时,渲染分页总数-7的连号页码,头部渲染省略...项及第1页。
- 其余情况则头尾都渲染省略...项,第1页及总分页数,中间渲染页码。
- 上一页和下一页按钮必定会出现,当前为第一页则禁用上一页,当前为最后一页则禁用下一页。
//省略项组件,接受点击事件和鼠标悬浮元素时的文字提示,antd的分页组件的省略项有鼠标悬浮元素时变化内容的效果,该组件没有考虑实现,可自行拓展
const PageOmit = (props) => {
return (
<li title={props.title} onClick={props.onClick && props.onClick}>
...
</li>
);
};
//初始化分页元素,代码中的函数事件后面有补充
initPage = () => {
const { nextBtnText, preBtnText } = this.props;
const { totalPageSize, currentPage } = this.state;
let contentList = [];
if (totalPageSize <= 9) {
contentList = Array.from({ length: 9 - 2 }).map((_, i) => {
return (
<li
onClick={() => this.pageChange(i + 1)}
className={currentPage === i + 1 ? "page-item-active" : ""}
key={i + Math.random()}
>
{i + 1}
</li>
);
});
} else if (currentPage + 4 >= totalPageSize) {
contentList = [
<li
key={"first" + Math.random()}
onClick={() => {
this.pageChange(1);
}}
>
1
</li>,
<PageOmit
key={"omit" + Math.random()}
onClick={this.preOmitPageChange}
/>,
].concat(
Array.from({ length: 9 - 2 }).map((_, i) => {
return (
<li
onClick={() => this.pageChange(i + totalPageSize - 9 + 3)}
className={
currentPage === i + totalPageSize - 9 + 3
? "page-item-active"
: ""
}
key={i + Math.random()}
>
{i + totalPageSize - 9 + 3}
</li>
);
})
);
} else if (currentPage - 4 <= 1) {
contentList = Array.from({ length: 9 - 2 })
.map((_, i) => {
return (
<li
onClick={() => this.pageChange(i + 1)}
className={currentPage === i + 1 ? "page-item-active" : ""}
key={i + Math.random()}
>
{i + 1}
</li>
);
})
.concat([
<PageOmit
key={"omit" + Math.random()}
onClick={this.nextOmitPageChange}
/>,
<li
key={"last" + Math.random()}
onClick={() => {
this.pageChange(totalPageSize);
}}
>
{totalPageSize}
</li>,
]);
} else {
// eslint-disable-next-line no-sparse-arrays
contentList = [
<li key={"first" + Math.random()} onClick={() => this.pageChange(1)}>
1
</li>,
<PageOmit
key={"omit" + Math.random()}
onClick={this.preOmitPageChange}
/>,
,
...Array.from({ length: 9 - 4 }).map((_, i) => {
return (
<li
onClick={() => this.pageChange(i + currentPage - 2)}
className={
currentPage === i + currentPage - 2 ? "page-item-active" : ""
}
key={i + Math.random()}
>
{i + currentPage - 2}
</li>
);
}),
<PageOmit
key={"omit" + Math.random()}
onClick={this.nextOmitPageChange}
/>,
<li
key={"last" + Math.random()}
onClick={() => this.pageChange(totalPageSize)}
>
{totalPageSize}
</li>,
];
}
contentList.unshift(
<li
className={currentPage === 1 ? "disabled" : ""}
onClick={this.prePageChange}
key={"pre"}
>
{preBtnText}
</li>
);
contentList.push(
<li
className={currentPage === totalPageSize ? "disabled" : ""}
onClick={this.nextPageChange}
key={"next"}
>
{nextBtnText}
</li>
);
return contentList;
};
相关事件函数
// 页码改变时,判断是否与当前页码相同,相同则不执行,不相同则改变当前页码并执行传入的回调,并把当前页码传给回调函数
pageChange = (currentPage) => {
const { currentPage: stateCurrentPage } = this.state;
if (currentPage === stateCurrentPage) return;
this.setState({ currentPage });
this.props.onPageChange.call(undefined, currentPage);
};
//下一页事件
nextPageChange = () => {
let { currentPage, totalPageSize } = this.state;
if (currentPage === totalPageSize) return;
this.pageChange(currentPage + 1);
};
//上一页事件
prePageChange = () => {
let { currentPage } = this.state;
if (currentPage === 1) return;
this.pageChange(currentPage - 1);
};
//向前5页的省略号事件
preOmitPageChange = () => {
const { currentPage } = this.state;
this.pageChange(currentPage - 5);
};
//向后5页的省略号事件
nextOmitPageChange = () => {
const { currentPage } = this.state;
this.pageChange(currentPage + 5);
};
快速跳转功能实现逻辑
- 输入框输入后点击回车执行校验,如果不为数字则只清空输入框,不执行后续代码
- 输入的值如果为数字则向下取整9,如输入5.9则视为5,并跳转到对应页码5
- 输入的值如果大于分页总数或小于1则跳转到分页总数或第一页
- 通用逻辑,如果跳转的页码和当前页码相同,则不执行后续代码
//快速跳转输入框绑定
inputChangeHandler = (event) => {
this.setState({ inputValue: event.target.value });
};
//快速跳转输入框按下回车事件
onInputKeyUp = (event) => {
if (event.keyCode === 13) {
//keyCode为13就是回车
const value = parseInt(event.target.value);
const { currentPage, totalPageSize } = this.state;
if (isNaN(value)) {
this.setState({
inputValue: "",
});
} else if (value > totalPageSize) {
//如果输入的合法数字大于总页数,则跳转至最后一页
if (totalPageSize === currentPage) {
//如果当前已经是第一页,则只清空输入框
this.setState({ inputValue: "" });
} else {
this.setState({ currentPage: totalPageSize, inputValue: "" });
this.props.onPageChange.call(undefined, totalPageSize);
}
} else if (value < 1) {
//如果输入的合法数字大于总页数,则跳转至最后一页
if (1 === currentPage) {
//如果当前已经是最后一页,则只清空输入框
this.setState({ inputValue: "" });
} else {
this.setState({ currentPage: 1, inputValue: "" });
this.props.onPageChange.call(undefined, 1);
}
} else if (this.state.currentPage === parseInt(value)) {
this.setState({ inputValue: "" });
} else {
this.setState({
inputValue: "",
currentPage: parseInt(value),
});
this.props.onPageChange.call(undefined, value);
}
}
};
最总的render代码
//渲染函数
render() {
const { inputValue } = this.state;
const { showQuickJumper, showTotal, total } = this.props;
return (
<div className="page-container">
//根据props的showTotal值决定是否展示总共多少条
{showTotal && (
<span
style={{ color: `#333`, marginRight: `.5em`, marginLeft: `1em` }}
>
共{total}条
</span>
)}
<ul className="page-wrapper">{this.initPage()}</ul>
//根据props的showQuickJumper值决定是否展示快速跳转输入框
{showQuickJumper && (
<div className="qucik-jump-wrapper">
跳至
<input
onKeyUp={this.onInputKeyUp}
value={inputValue}
onChange={this.inputChangeHandler}
/>
页
</div>
)}
</div>
);
}
附上样式代码
import React, { Component } from "react";
import "./page.css";
//在组件头部引入样式
//下面为样式代码
.page-container {
display: flex;
font-size: 14px;
align-items: center;
padding: 4px 0;
}
.page-wrapper {
display: flex;
margin-left: .5em;
align-items: center;
}
.page-wrapper li.page-item-active {
color: #1890ff;
border-color: #1890ff;
}
.page-wrapper li {
border: 1px #d9d9d9 solid;
cursor: pointer;
padding: 4px 12px;
margin-right: .5em;
margin-left: .5em;
color: #272727;
border-radius: 2px;
}
.page-wrapper li:hover {
color: #1890ff;
border-color: #1890ff;
}
.page-wrapper li.disabled {
color: rgba(0, 0, 0, .25);
border-color: #d9d9d9;
cursor: not-allowed;
}
.qucik-jump-wrapper {
margin-left: 1em;
}
.qucik-jump-wrapper input {
transition: all .3s;
width: 40px;
padding: 4px 8px;
border: 1px solid #d9d9d9;
margin: 0 8px;
border-radius: 2px;
line-height: 1.45;
}
.qucik-jump-wrapper input:focus, .qucik-jump-wrapper input:hover {
border-color: #40a9ff;
border-right-width: 1px!important;
outline: 0;
box-shadow: 0 0 0 2px rgba(24, 144, 255, .2);
}
使用分页组件
import Page from "./components/Page";
// 组件代码省略
render(){
<Page
total={100} //传入总共多少条
//currentPage={1} //传入当前第几页
// 上一页及下一页的文字可自定义,不传入则为<和>
// preBtnText={'上一页'}
// preBtnText={'下一页'}
onPageChange={(e) => {
// ...业务逻辑
}} //传入页码改变时的回调函数
/>
}
最后来看看实现的效果吧
奉上Github源码地址,觉得有帮助的不妨点个Star支持下~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!