β

React版博客系列4--Article组件与ArticleList组件

繁星UED 93 阅读

系列链接:

1. React版博客系列1--基础说明与标签组件
2. React版博客系列2--分页组件设计
3. React版博客系列3--路由系统
4. React版博客系列4--Article组件与ArticleList组件

先上demo

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

接上篇

react-router骨架已经搭好,博客的主体部分为显示博文已经相关的操作。查看归档、分页、显示单篇文章等。
个人自定义一页显示三篇博文,所以,ArticleList组件内包含三个Article组件,当然,这个不会写死。 先看Article 的render方法,这里使用了html5的新标签article, this.props.route 这个判断的作用是让Article组件知道,目前所处的状态是查看单篇文章(Article自己根据文章名称读取接口)还是多篇文章组合(ArticleList读取相应的接口,把每篇文章的内容通过props传递进来):

render(){  
    if(this.props.route){
      return (
        <article>
          <header>
            <h2>
              <a href="http://ued.fanxing.com/blog-react-articleandarticlelist/">{this.state.title}</a>
            </h2>
          </header>
          <div className="article-meta clearfix">
            <time className="left">{this.state.timeStr}</time>
            <ul className="tags left"></ul>
            <ul className="tags right">
              {
                this.state.tags.map(function(item,index){
                  return (<li><Link to={"/tag"+"/"+item.tag+"/"}>{item.tagName}</Link></li>)
                })
              }
            </ul>
          </div>
          <div className="markdown-body" dangerouslySetInnerHTML={{__html: this.state.post}}>
          </div>
        </article>
      )
    }else{
      return(
        <article>
          <header>
            <h2>
              <Link to={"/"+this.props.articleModel.time.year+"/"+this.props.articleModel.time.month+"/"+this.props.articleModel.name}>{this.props.articleModel.title}</Link>
            </h2>
          </header>
          <div className="article-meta clearfix">
            <time className="left" >{this.props.articleModel.timeStr}</time>
            <ul className="tags right">
              {
                this.props.articleModel.tags.map(function(item,index){
                  return (<li key={index}><Link to={"/tag"+"/"+item.tag+"/"}>{item.tagName}</Link></li>)
                })
              }
            </ul>
          </div>
          <div className="markdown-body" dangerouslySetInnerHTML={{__html: this.props.articleModel.post}}>
          </div>
        </article>
      )
    }
  }

那相应的,Article获取文章内容的方法如下:

    componentDidMount(){
    this.getArticle();
  }

    getArticle(){
    let self = this;
    let url = Settings.getServiceUrl();
    //判断是否是从router进入 从router进入这是是undefined
    if(this.props.params){
      url = url + '/' + this.props.params.year + '/' + this.props.params.month + '/' + this.props.params.name;
      $.ajax({
        url:url,
        type:'GET',
      }).done(function(result){
        self.setState({
          title:result.article.title,
          timeStr:result.article.timeStr,
          tags:result.article.tags,
          post:result.article.post
        });
      }.bind(self));
    }
  }

ArticleList组件

ArticleList组件除了管理Article之外,还需管理分页组件,关于分页组件,请查看本系列第二篇 React版博客系列2--分页组件设计
核心方法getArticleList:

    componentDidMount(){
    this.getArticleList(this.props);
  }
  componentWillReceiveProps(nextProps){
    this.getArticleList(nextProps);
  }

  getArticleList(props){
    let self = this;
    let url = Settings.getServiceUrl();
    let queryType = props.route.to.queryType;
    switch(queryType){
      case '/':
        if(props.params.pageIndex){
          url = url + '/page/' + props.params.pageIndex + '/';
        }
      break;
      case 'tag':
        let keyword = props.params.tag;
        url = url + '/tag/' + keyword + '/';
        if(props.params.pageIndex){
          url = url + 'page/' + props.params.pageIndex + '/';
        }
      break;
      case 'archive':
        url = url + '/' + props.params.year + '/' + props.params.month + '/';
        if(props.params.pageIndex){
          url = url + 'page/' + props.params.pageIndex + '/';
        }
      break;
    }
    $.ajax({
      url:url,
      type:'GET',
      cache:false
    }).done(function(result){
        self.setState({
          queryType:queryType,
          list:result.list,
          pageIndex: result.pagination.pageIndex,
          pageCount: result.pagination.pageCount,
          prefix: result.pagination.prefix||''
        });
    }.bind(self));
  }

getArticleList需要根据不同的参数查询不同的文章列表,比如普通分页、标签分页、归档分页等,而这些都是由上层的骨架router传递进来的,所以有了queryType变量,并提取出查询的具体参数。同样的,分页组件亦需要依赖于这些参数构建分页的前缀等:

    render(){
    return(
        <div>
          {
            this.state.list.map(function(item,index){
              return <Article articleModel={item} key={index} />
            })
          }
          <Pagination onChange={this.onChange} pageIndex={this.state.pageIndex} pageCount={this.state.pageCount} prefix={this.state.prefix} />
        </div>
      );
  }

ArticleList组件的完成意味着打通了从router到Article的全部展示流程,其中实现了自己的分页、标签、归档功能,当然,还包括了几个没那么核心的header、copyright、information组件等,一个说简单也不简单的博客系统已经初步完成,react为前端同学提供了一整套组件化思路,各位可以按照自己的想法实现自己的网站。

后记

至此,React版博客系列系列已经完结,github上也早已开源了全部源码 blog_react ,要查看某些具体的细节,欢迎clone下来交流。 围绕React,亦产生了一整套单向数据流(flux、reflux、redux)。本系列并不打算讲任何一种单向数据流方案,因为在理解了react思路之后,flux、reflux、redux其实十分简单,根据口味自行选用即可。

作者:繁星UED
Thoughts, stories and ideas.
原文地址:React版博客系列4--Article组件与ArticleList组件, 感谢原作者分享。