美文网首页React
一步一步教你写 React 分页组件(五)

一步一步教你写 React 分页组件(五)

作者: 柏丘君 | 来源:发表于2017-05-11 21:51 被阅读366次
    • 此分页组件已发布至NPM,欢迎下载并提意见

    上篇文章主要处理了 startPage,也就是前7个页码从哪里开始的问题。本文将在前面的基础上做一些细节的优化,主要是:

    • 处理省略符的问题
    • 点击最后两页的问题
    • 实现自定义 select

    解决这三个问题,我们的分页就算基本完成了。

    处理省略符

    省略符的问题比较简单,只需在原有的基础上增加一个条件判断。修改 create 方法:

    ...
    // 分页中间的省略符
    if(totalPage - startPage >= 9){
        pages.push(<li className = { style.ellipsis } key={ -1 }>···</li>)
    }
    ...
    
    

    这样一来,当页面上的页码数目小于10个时,就不添加省略符。效果如图:

    处理省略号.gif

    点击最后两页

    我们想在点击最后两页时,也进行响应,最好是点击后把其前面的几页也显示出来。
    当前的效果是:点击第20页没反应,点击第21页显示了其前面的几页,这是因为21刚好为7的倍数,在点击后重新计算了startPage(请参考前一篇文章)。这是偶然因素,实际情况下不可能这么巧合,因此我们需要针对最后两页再做单独的处理。
    在 go 方法中增加判断:

    ...
    // 更新 state
    go(pageCurr){
        const {
            groupCount
        } = this.state;
        // 获取总页数
        const {
            totalPage
        } = this.props.config
        
        // 处理上一页的情况
        ...
        // 处理下一页的情况
        ...
    
        // 点击最后两页时重新计算 startPage
        if(totalPage - pageCurr < 2){
            this.setState({
                startPage:totalPage - groupCount,
            })
        }
        this.setState({
            pageCurr
        });
    }
    ...
    

    修改 create 方法,主要是修正组件 key 值的问题:

    ...
    for(let i = startPage;i < groupCount + startPage;i ++){
        if(i <= totalPage - 2){
            pages.push(<li className = { this.state.pageCurr === i? style.active:""} key={i} onClick = { this.go.bind(this,i) }>{i}</li>)
        }
    }
    ...
    

    至此,页码部分基本处理完毕,下面是完成效果:

    点击后两页进行处理.gif

    趁热打铁

    页码部分基本算是写完了,虽然在体验上还有需要优化的地方,但基本的使用应该是可以了。下面我们趁热打铁,完成左边的自定义 select。
    修改 render 方法:

    ...
    render(){
        const Pages = this.create.bind(this)();
        return(
            <div className = { style.main }>
                <div className = { style.bar }>
                    <span>每页显示</span>
                    <div className = { style.select }>
                        <ul>
                            <li id="pageCount">10</li>
                            <li>10</li>
                            <li>20</li>
                            <li>30</li>
                            <li>50</li>
                        </ul>
                    </div>
                </div>
                <ul className = { style.page }>
                    { Pages }
                </ul>
            </div>
        );
    }
    ...
    

    增加样式:

    ...
    // 下拉菜单
    .bar{
        display: flex;
        justify-content:space-between;
        align-items:flex-start;
        color:#666;
        span{
            font-size: 12px;
        }
    }
    .select{
        width:48px;
        height:calc(6 * 22px);
        background: #fff;
        margin-left:10px;
        ul{
            height:100%;
            display: flex;
            flex-direction:column;
            justify-content:space-between;
            list-style: none;
            border:1px solid #e6e6e6;
            padding:0;
            margin:0;
            li{
                padding:3px 0;
                padding-left:5px;
                &:hover{
                    background: #54b0bd;
                }
                &:first-of-type{
                    border-bottom:1px solid #e6e6e6;
                    position: relative;
                    &::after{
                        content:"";
                        display: block;
                        width:7px;
                        height:25px;
                        background: url("./imgs/dropdown.png") no-repeat center center;
                        position: absolute;
                        top:0;
                        right:5px;
    
                    }
                }
            }
        }
    }
    // 收起状态
    ul.hide{
        height:24px;
        overflow: hidden;
        li{
            &:nth-of-type(n+2){
                display: none;
            }
        }
    }
    

    效果如图:

    自定义select.gif

    若我们给 ul 应用 .hide 样式,就可以将其收起。

    添加点击事件

    处理页面点击事件,点击空白处收起 ul,我们可以在 componentDidMount 后添加点击事件:

    ...
    componentDidMount() {
        this.setState({
            pageCountEle:document.querySelector("#pageCount"),
        });
    
        setTimeout(()=>{
            document.addEventListener("click",(e)=>{
                if(e.target.id !== "pageCount"){
                    this.state.pageCountEle.parentNode.className = style.hide;          
                }
            },false);
        },0)
    }
    ...
    

    使用 setTimeout 的原因是因为 state 并不保证是及时更新的,因此我们需要将一些操作放在异步队列中执行。下面的代码中还会看到这种用法。
    题外话:setState 是异步方法,其还可以接受一个函数作为参数,用来在完成 state 设置后回调。
    增加 choosePageCount 方法,用来展开 ul:

    ...
    choosePageCount(e){
        const parentUI = this.state.pageCountEle.parentNode;
        parentUI.className = (parentUI.className === style.hide)?"":style.hide;
    }
    ...
    

    增加 confirmPageCount 方法,在选择分页条数后进行处理。

    ...
    confirmPageCount(pageCount){
        const {
            pageCountEle,
            pageCurr,
        } = this.state;
    
        // 设置每页显示条数
        this.setState({
            pageCount
        });
        pageCountEle.innerHTML = pageCount;
        pageCountEle.parentNode.className = style.hide;
    
        setTimeout(()=>{
            this.go(pageCurr, true);
        },0);
    }
    ...
    

    注意:选择每页显示条数后将重置当前页码(pageCurr)至第1页,因此我们还需要对 go 方法再做一些修改:

    ...
    // 更新 state
    go(pageCurr,reset = false){
        ...
        // 处理上一页的情况
        ...
    
        // 处理下一页的情况
        ...
    
        // 点击最后两页时重新计算 startPage
        ...
    
        // 选择每页条数后重新分页
        if(reset === true){
            this.setState({
                pageCurr:1,
                startPage:1,
            });
        }
    }
    ...
    

    最后,修改 render 方法,增加事件处理:

    ...
    render(){
        const Pages = this.create.bind(this)();
        return(
            <div className = { style.main }>
                <div className = { style.bar }>
                    <span>每页显示</span>
                    <div className = { style.select }>
                        <ul className = { style.hide }>
                            <li id="pageCount" onClick = { this.choosePageCount.bind(this) }>10</li>
                            <li onClick = { this.confirmPageCount.bind(this,10) }>10</li>
                            <li onClick = { this.confirmPageCount.bind(this,20) }>20</li>
                            <li onClick = { this.confirmPageCount.bind(this,30) }>30</li>
                            <li onClick = { this.confirmPageCount.bind(this,50) }>50</li>
                        </ul>
                    </div>
                </div>
                <ul className = { style.page }>
                    { Pages }
                </ul>
            </div>
        );
    }
    ...
    

    至此,整个分页效果就完成了,下面是最终效果:

    final.gif

    从效果上来说,我们的分页组件已经写完了,是不是有点小小的成就感呢?那就赶快试一试吧!
    再接下来就是处理实际问题了——与后端交互,获取数据。我将在下一篇文章为大家进行介绍。

    完。

    一步一步教你写 React 分页组件(一)
    一步一步教你写 React 分页组件(二)
    一步一步教你写 React 分页组件(三)
    一步一步教你写 React 分页组件(四)
    一步一步教你写 React 分页组件(五)
    一步一步教你写 React 分页组件(六)

    相关文章

      网友评论

        本文标题:一步一步教你写 React 分页组件(五)

        本文链接:https://www.haomeiwen.com/subject/shratxtx.html