手撸一个Pagination分页器组件

1,144 阅读1分钟

前言

分页器组件经常与Table组件一起使用,所以也算是一个常用的组件吧,这次咱就来碰一碰它。

市面组件分析

老样子还是以市面上的组件来作切入点,这次咱们就选择antd,现对Antd分析如下:

一、当总页码数 <= 5

分页器1.png

结论1:

当总也码数 <= 5时,无论你怎么点击分页器里的按钮,它都会全部显示出来

二、当总页码数很多(比如总页数是50)

  • 2.1、当选中的页码 < 5时的情况

分页器3.png

  • 2.2、当选中的页码 >= 5 && <= 46时的情况

分页器6.png

分页器4.png

  • 2.3、当选中的页码 >= 47 && <= 50时的情况

分页器5.png

结论2

当页码较多时,需要根据临界值(由开发者自己控制)来做相应的展示。

三、组件实现

我们再来捋一下antd的思路:

  • 页码较小时,全部展示
  • 页码较多时,根据临界值做相应展示

3.1、伪代码思路

    /*
        @param { Number }  totalData            总数据量
        @param { Number }  everyPageDataCount   每页渲染多少条数据
        @param { Number }  currentPage          当前所在页
        @description
           1、如果totalData <= 10,则全部渲染出来
           2、如果totalData > 10, 比如 totalData == 11, 那么此时分为3种情况
              2.1、如果此时 currentPage < 5 或者 currentPage >= totalPage - 2,那么此时展现的结果应该是这样: 
                   1 2 3 4 ... 9 10 11
              2.2、如果此时 5 <= currentPage < totalPage - 2, 那么此时展现的结果应该是像下面这种形式:
                   2.2.1、currentPage == 5,1 ... 3 4 5 6 7 ... 11
                   2.2.2、currentPage == 6,1 ... 4 5 6 7 8 ... 11
                   2.2.3、currentPage == 7,1 ... 5 6 7 8 9 ... 11
                   ...
                   看到这有些观众基本上猜出来了,中间的我个数就是currentPage++--得来的
    **/
   const createPagination = function (totalData, everyPageDataCount, currentPage){
       // 得到总页码数
       let totalPage = Math.ceil(totalData / everyPageDataCount);
       
       if ( (currentPage < 5) || ( ( currentPage >= totalPage - 1) && (currentPage < totalData) ) ){
          // render something    
       } else {
          // 1、初始化中间元素数组
          const slidingWindow = [];
          // 2、根据currentPage来动态获取中间元素
          for (let index = -2; index <= 2; index++){
              const text = document.createTextNode(currentPage + index);
              const page = document.createElement('div');
              page.appendChild(text);
              slidingWindow.push(page);
          }
          // render something
          for (let index = 0; index < slidingWindow.length; index++){
              document.querySelector('.box').appendChild(slidingWindow[index])
          }
       }
   }

3.2、全部代码

html、css如下:

<! DOCTYPE html>
<html>
    <head>
        <title>分页器</title>
        <meta charset='utf-8'>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            html, body {
                width: 100%;
                height: 100%;
            }
            .prevIcon {
                width: 7px;
                height: 7px;
                border-top: 1px solid #ccc;
                border-left: 1px solid #ccc;
                transform: rotate(-45deg);
            }
            .nextIcon {
                width: 10px;
                height: 10px;
                border-top: 1px solid #ccc;
                border-right: 1px solid #ccc;
                transform: rotate(45deg);
            }
            .page {
                width: 20px;
                height: 20px;
                border: 1px solid #ccc;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .selectedPage {
                border: 1px solid cornflowerblue;
            }
        </style>
    </head>
    <body>
        <div class = 'pagination'></div>
    </body>
</html>

js代码如下:

    const createPagination = function (totalData, everyPageDataCount, currentPage){
            // 清空box的子元素
            document.querySelector('.box').innerHTML = '';
            // 得到总页码数
            let totalPage = Math.ceil(totalData / everyPageDataCount);
            // 渲染dom集合
            let renderDomList = [];

            // 上一页dom
            const prevIcon = document.createElement('div');
            prevIcon.classList.add('prevIcon');
            const prevDiv = document.createElement('div');
            prevDiv.classList.add('page');
            prevDiv.classList.add('qianjin');
            prevDiv.appendChild(prevIcon);

            // 创建下一页dom
            const nextIcon = document.createElement('div');
            nextIcon.classList.add('nextIcon');
            const nextDiv = document.createElement('div');
            nextDiv.classList.add('page');
            nextDiv.classList.add('houtui');
            nextDiv.appendChild(nextIcon);

            // 创建省略号1
            const ellipsisIcon1 = document.createTextNode('...');
            const ellipsisDiv1 = document.createElement('div');
            ellipsisDiv1.classList.add('page');
            ellipsisDiv1.appendChild(ellipsisIcon1);

            // 创建省略号2
            const ellipsisIcon2 = document.createTextNode('...');
            const ellipsisDiv2 = document.createElement('div');
            ellipsisDiv2.classList.add('page');
            ellipsisDiv2.appendChild(ellipsisIcon2);

            if (totalPage <= 10){
                let renderPageList = [];
                for (let index = 1; index <= totalPage; index++){
                    const text = document.createTextNode(index);
                    const page = document.createElement('div');
                    page.classList.add('page');
                    page.appendChild(text);
                    renderDomList.push(page);
                }
                renderDomList = [prevDiv].concat(renderPageList, [nextDiv]);

                // 渲染dom
                for (let index = 0; index < renderDomList.length; index++){
                    document.querySelector('.box').appendChild(renderDomList[index]);
                }
                return 
            }

            if ( (currentPage < 5) || ( ( currentPage >= totalPage - 2) && (currentPage < totalData) ) ){
                const firstDiv = [];
                const finalDiv = [];
                for (let index = 1; index <= 4; index++){
                    const text = document.createTextNode(index);
                    const page = document.createElement('div');
                    page.appendChild(text);
                    page.classList.add('page');
                    if (index == currentPage){
                        page.classList.add('selectedPage');
                    }
                    firstDiv.push(page);
                };
                for (let index = totalPage -2 ; index <= totalPage;index++){
                    const text = document.createTextNode(index);
                    const page = document.createElement('div');
                    page.appendChild(text);
                    page.classList.add('page');
                    if (index == currentPage){
                        page.classList.add('selectedPage');
                    }
                    finalDiv.push(page);
                }
                renderDomList = [prevDiv].concat(firstDiv, [ellipsisDiv1], finalDiv, [nextDiv]);
            } else {
                // 创建第一个页码元素
                const firstIcon = document.createTextNode(1);
                const firstDiv = document.createElement('div');
                firstDiv.classList.add('page');
                firstDiv.appendChild(firstIcon);

                // 创建最后的页码元素
                const finalIcon = document.createTextNode(totalPage);
                const finalDiv = document.createElement('div');
                finalDiv.classList.add('page');
                finalDiv.appendChild(finalIcon);

                let slidingWindow = [];
                if ( (currentPage + 2) == ( totalPage - 1 )){
                    slidingWindow = [];
                    for (let index = -2; index <= 3; index++){
                        const text = document.createTextNode(currentPage + index);
                        const page = document.createElement('div');
                        page.classList.add('page');
                        if ((currentPage + index) == currentPage){
                            page.classList.add('selectedPage');
                        }
                        page.appendChild(text);
                        slidingWindow.push(page);
                    }
                    renderDomList = [prevDiv].concat([firstDiv], [ellipsisDiv1], slidingWindow, [nextDiv]);
                } else {
                    for (let index = -2; index <= 2; index++){
                        const text = document.createTextNode(currentPage + index);
                        const page = document.createElement('div');
                        page.classList.add('page');
                        if ((currentPage + index) == currentPage){
                            page.classList.add('selectedPage');
                        }
                        page.appendChild(text);
                        slidingWindow.push(page);
                    }
                    renderDomList = [prevDiv].concat([firstDiv], [ellipsisDiv1], slidingWindow, [ellipsisDiv2], [finalDiv], [nextDiv]);
                }
            }
            // 渲染元素
            for (let index = 0; index < renderDomList.length; index++){
                document.querySelector('.box').appendChild(renderDomList[index]);
                // 监听事件
                renderDomList[index].onclick = function (e){
                    if (e.target.classList.contains('qianjin') || e.target.classList.contains('prevIcon')){
                        createPagination(totalData, everyPageDataCount, currentPage - 1);
                    } else if (e.target.classList.contains('houtui') || e.target.classList.contains('nextIcon')){
                        createPagination(totalData, everyPageDataCount, currentPage + 1);
                    } else {
                        createPagination(totalData, everyPageDataCount, Number(e.target.innerText));
                    }
                }
            }
        }
        

补充:

别忘记了边界处理,1 和 totalPage 是不可以点击上一页或者下一页噢

最后

1、上面只是提供一个思路

2、写到这忽然有个想法,我是否应该写一个专栏,这个专栏专门服务于组件

3、发现自己的拖延症是真的严重,一篇文章竟然可以拖一周