β

React版博客系列2--分页组件设计

繁星UED 288 阅读

系列链接:

1. React版博客系列1--基础说明与标签组件
2. React版博客系列2--分页组件设计

先上Demo

本系列源码: blog react
数据服务: blogapi
线上预览: http://react.nullcn.com

接上篇

本来打算写Archive组件的,不过考虑到Archive组件跟Tags组件其实就是换汤不换药,这种如果单独开一篇来讲,这系列水就深了。 通常来说,分页除了渲染(比如页码如何显示)之外,几乎不需要什么功能,当然在考虑到分页空间一般从属于某个列表,也就是说需要当前页(必须),总页数(非必须),在放到特定的业务里,比如需要分页组件记录并使用分页前缀(~/tag/javascript)。另外,分页组件如果需要单独使用,则还需要通知上层组件,所以会有个事件通讯,当然,本博客内的分页组件具备该功能但并未使用,原因另说。先看代码:

//https://github.com/mywei1989/blog_react/blob/master/assets/blog/js/Pagination.js
  constructor(props){
    super(props);

    let pageIndex = props.pageIndex||1;
    let pageCount = props.pageCount||1;
    let prefix = props.prefix||'/';
    this.state={
      pageIndex:pageIndex,
      pageCount:pageCount,
      prefix:prefix
    }
  }

这里很好理解,定义改组件的构造函数,并默认设置了3个参数。

该方法为react内置方法,作用为"已加载组件收到新的参数时调用",因为上层组件(列表)如果因为某种原因触发了render,则可能调用该方法,重置3个默认值。这里顺带提一句,props与state的区别:由于props和state都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,props表示那些一旦定义,就不再改变的特性,而state是会随着用户互动而产生变化的特性。在调用setState时,react会自动触发render事件。

//https://github.com/mywei1989/blog_react/blob/master/assets/blog/js/Pagination.js
componentWillReceiveProps(nextProps){  
    this.setState({
      pageIndex:nextProps.pageIndex,
      pageCount:nextProps.pageCount,
      prefix:nextProps.prefix
    });
  }

通知上层组件的接口

_handleChange(pageIndex){  
    this.props.onChange(pageIndex);
}

最后是render方法,该方法这么多完全是我想实现一套自己的展示方式,即根据pageCount与pageIndex不同,根据自己需要的逻辑渲染出不一样的分页效果:

render(){

    let pageHtml=[];
    if(this.props.pageIndex>1){
      if(this.props.pageIndex-1===1){
        pageHtml.push(<a className="extend prev" rel="prev" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/"} key="«">«</a>);
      }else{
        pageHtml.push(<a className="extend prev" rel="prev" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+(this.props.pageIndex-1)+"/"} key="«">«</a>);
      }
    }
    if(this.props.pageIndex===2){
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/"} key="1">1</a>);
    }else if(this.props.pageIndex===3){
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/"} key="1">1</a>);
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/2/"} key="2">2</a>);
    }else if(this.props.pageIndex===4){
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/" key="1">1</a>);
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/2/" } key="2">2</a>);
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/3/" } key="3">3</a>);
    }else if(this.props.pageIndex===5){
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/" key="1">1</a>);
      pageHtml.push(<span className="space" key="...">…</span>);
      for(let i=this.props.pageIndex-2;i<this.props.pageIndex;i++){
        pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+i+"/" } key={i}>{i}</a>);
      } 
    }
    pageHtml.push(<span className="page-number current" key={this.props.pageIndex} key={this.props.pageIndex}>{this.props.pageIndex}</span>);
    if(this.props.pageCount - this.props.pageIndex >= 4){
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+(this.props.pageIndex+1)+"/"} key={this.props.pageIndex+1} key={this.props.pageIndex+1} >{this.props.pageIndex+1}</a>);
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+(this.props.pageIndex+2)+"/"} key={this.props.pageIndex+2} key={this.props.pageIndex+2} >{this.props.pageIndex+2}</a>);
      pageHtml.push(<span className="space" key="...">…</span>);
      pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+this.props.pageCount+"/"} key={this.props.pageCount}>{this.props.pageCount}</a>);
    }else{
      for(let i=this.props.pageIndex+1;i<=this.props.pageCount;i++){
        pageHtml.push(<a className="page-number" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+i+"/"} key={i}>{i}</a>);
      }
    }
    if(this.props.pageIndex!==this.props.pageCount){
      pageHtml.push(<a className="extend next" rel="next" href="http://ued.fanxing.com/blog-react-2/{this.props.prefix+""/page/"+(this.props.pageIndex+1)+"/"} key="»">»</a>);
    }


    return(
     <div className="archive-pagination">
        <div className="paginator">
        {pageHtml}
        </div>
      </div>
    )
  }

render方法里为何没有使用_handleChange方法?

因为出于全局的考虑,并不打算通知上层翻页,而是通过更上层的react-router方式,这里附上使用通知上层的方法与调用方式:

//上层组件
<Pagination onChange={this.onChange} pageIndex={this.state.pageIndex} pageCount={this.state.pageCount} prefix={this.state.prefix} />


//Pagination.js
render(){  
     return (
        <a className="page-number" href="http://ued.fanxing.com/blog-react-2/" onClick={this._handleChange(3)}>3</a>
     );
}

当然,我们还可以扩展一下,比如上一页:

  _prev(){
    if(this.state.pageIndex>1){
      this._handleChange(this.state.pageIndex-1);
    }else{
      this._handleChange(1);
    }
  }

如果想定制不同的风格,比如分页省略号的位置等等,可以使用上层组件,通过props方式传递给分页组件。 当然,分页组件也不限定使用a标签,其他的标签一样可以。

下篇预告

下篇的内容将会是引入react-router,并对react-router做一些必要的说明,可能是本系列最重要的一篇,基于react-router将该博客构建成SPA的页面。之后,会改造工程结构,开发Article(文章)组件并将他们组合起来。 现在可以直接看看目前本人react博客的线上效果: http://react.nullcn.com

作者:繁星UED
Thoughts, stories and ideas.
原文地址:React版博客系列2--分页组件设计, 感谢原作者分享。

发表评论