最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React造轮子系列--参照AntDesign实现Pagination分页组件

    正文概述 掘金(MongieLee)   2020-12-26   827

    代码使用class组件编写

    下图为最终基本样式,文章最后有组件使用预览GIf图,UI及配色参照了antd的Pagination组件 React造轮子系列--参照AntDesign实现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: "", //快速跳转输入框值
        };
      }
    

    渲染出分页组件的主要元素

    主要实现逻辑:

    1. 总分页数<=9条时全部展示,直接渲染出全部页码即可。当总页数>9条时,必定出现省略项...,只是位置有所区别,点击省略项功能参考antd的,默认(+/-)5个页码。
    2. 当前页数减去4(4为单边最多出现的兄弟项数量)<=1时,渲染1-7的连号页码,尾巴渲染省略...项及总分页数。
    3. 当前页数加上4(4为单边最多出现的兄弟项数量)>=总页数时,渲染分页总数-7的连号页码,头部渲染省略...项及第1页。
    4. 其余情况则头尾都渲染省略...项,第1页及总分页数,中间渲染页码。
    5. 上一页和下一页按钮必定会出现,当前为第一页则禁用上一页,当前为最后一页则禁用下一页。
    //省略项组件,接受点击事件和鼠标悬浮元素时的文字提示,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);
      };
    

    快速跳转功能实现逻辑

    1. 输入框输入后点击回车执行校验,如果不为数字则只清空输入框,不执行后续代码
    2. 输入的值如果为数字则向下取整9,如输入5.9则视为5,并跳转到对应页码5
    3. 输入的值如果大于分页总数或小于1则跳转到分页总数或第一页
    4. 通用逻辑,如果跳转的页码和当前页码相同,则不执行后续代码
      //快速跳转输入框绑定
      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) => {
          // ...业务逻辑
        }} //传入页码改变时的回调函数
      />
    }
    

    最后来看看实现的效果吧

    React造轮子系列--参照AntDesign实现Pagination分页组件

    奉上Github源码地址,觉得有帮助的不妨点个Star支持下~

    起源地下载网 » React造轮子系列--参照AntDesign实现Pagination分页组件

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元