13、React系列之--微博Demo 02 終結(jié)篇

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

PS:轉(zhuǎn)載請(qǐng)注明出處
作者:TigerChain
地址:http://www.itdecent.cn/p/9fddf666b718
本文出自TigerChain簡(jiǎn)書

React 教程系列

教程簡(jiǎn)介

  • 1、閱讀對(duì)象

本篇教程適合有React基礎(chǔ)的朋友閱讀(基礎(chǔ)知道 state,props, 組件化思想,webpack+yarn 等),老鳥直接略過,如果有誤,歡迎指出,謝謝。

正文

經(jīng)過上一篇學(xué)習(xí),我們把微博 Demo 的雛形搭建出來了,那把接下來我們把微博后面的內(nèi)容帶大家手把手全部做完。我們接著上一節(jié)的步驟繼續(xù)學(xué)習(xí)

5、添加頭像組件

  • 1、在項(xiàng)目的根目錄新建 img 文件夾并且放入三張圖片 (具體在demo中去查看)
imgs.png
  • 2、修改 WeiBoListItem.js

只添加一句代碼,就是進(jìn)入一張圖片并且設(shè)置樣式,這里就不貼代碼了,看圖即可。

import_avator.png

如圖所示,其中黃色部分就是我們引入一張圖片,并設(shè)置樣式,大家應(yīng)該想到了還要去設(shè)置樣式,沒錯(cuò)。

  • 3、修改 ListItemStyle.css ,添加以下樣式即可
.imgStyle{
  width: 80px;
  height: 80px;
  border-radius: 40px;
  margin-right: 10px;
}
  • 4、yarn start 跑一下,如果沒有什么問題,會(huì)報(bào)如下錯(cuò)
error_import_img.png

從圖中我們可以清楚的看到報(bào)錯(cuò)的原因,就是我們加載不了圖片,給我們的建議是下面這條紅線中說的,我們需要 loader 去處理文件類型。loader 我們不陌生,我們?nèi)グ惭b即可。提前說一下,在這里我們要安裝兩個(gè) loader 分別是 url-loader 和 file-loader (都是用于打包文件和圖片)。關(guān)于 url-loader 和 file-loader 的區(qū)別 請(qǐng)查看:url-loader和file-loader加載器有什么區(qū)別?

  • 5、安裝 url-loader 和 file-loader。
yarn add url-loader file-loader --dev

安裝了 loader 以后肯定要在 webpack.config.js 中去配置。

  • 6、添加 url-loader file-loader 到 webpack.config.js 中去
{
       test: /\.(png|jpg)$/,
       loader: 'url-loader?limit=8192'
}

將以上內(nèi)容添加到 webpack.config.js loaders 標(biāo)簽中,這沒什么好說的。

  • 7、運(yùn)行項(xiàng)目 yart-start

我們就會(huì)看到如下界面

avator_weibo_list.png

我們?nèi)缙诎杨^像加載進(jìn)來了。

6、添加評(píng)論列表組件

我們?cè)陧?xiàng)目 app 目錄新建 評(píng)論組件 CommentForm.js

# CommentForm.js


import React, { Component, PropTypes } from 'react';

// 導(dǎo)入評(píng)論的樣式
import styles from '../css/commentStyle.css';


/**
 * 取得當(dāng)前時(shí)間
 * @return {[type]} [description]
 */
function getCurrentFormatDate() {
    var date = new Date() ;
    var seperator1 = "-" ;
    var seperator2 = ":" ;
    var month = date.getMonth() + 1 ;
    var strDate = date.getDate() ;
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (strDate >= 0 && strDate <= 9) {
        strDate = "0" + strDate;
    }
    var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
            + " " + date.getHours() + seperator2 + date.getMinutes()
            + seperator2 + date.getSeconds();
    return currentdate;
}

/**
 * 評(píng)論組件
 */
export default class CommentForm extends Component {
  constructor(props) {
    super(props);
    this.state =  {
      //默認(rèn)回復(fù)內(nèi)容為空
      replycontents:[],
    }
  }

  render() {
    //遍歷評(píng)論內(nèi)容
    var replyContentDatas = this.state.replycontents.map(function(data,index) {
     return(
       //  <CommentReplyList key={index} reply={data}/>
       <div key={index}>
         <div>
           {/* 回復(fù)姓名 */}
            <span>{data.name}</span>
            {/* 回復(fù)內(nèi)容 */}
            <span>{data.content}</span>
          </div>
          {/* 回復(fù)時(shí)間 */}
            <span>{data.time}</span>
      </div>
     );
   });

   return (
      <div className={styles.rootView}>
        <div className={styles.headView}>
          {/* 回復(fù)的頭像 */}
            <img src={require('../img/qiche.jpg')} className={styles.img} />
          {/* 回復(fù)的文本框 */}
            <div className={styles.textareaViewStyle}>
              <textarea cols='4' rows='4' ref="content"/>
              <button className={styles.commentBtnStyle} onClick={this._reply.bind(this)}>評(píng)論</button>
            </div>
        </div>
        {/* 回復(fù)內(nèi)容 */}
            {replyContentDatas}
      </div>
     );
  }

  /**
   * 回復(fù)評(píng)論功能
   */
  _reply(){
      //取得當(dāng)前時(shí)間
      let currentTime = getCurrentFormatDate();
      //取得回復(fù)的內(nèi)容
      let recontent = this.refs.content.value;
      if(recontent.length==0){
        alert('評(píng)論內(nèi)容不能為空!')
        return ;
      }
      let newContent = {
        content:recontent,
        name:'軍軍',
        time:currentTime,
      }
      //取得老的回復(fù)內(nèi)容
      let oldRepContent = this.state.replycontents,
      //新的回復(fù)內(nèi)容和老的回復(fù)內(nèi)容疊加起來
      newRplContent = oldRepContent.concat(newContent);//數(shù)組的疊加
      //
      this.setState({
          replycontents:newRplContent,
      });
      //輕空輸入框內(nèi)容
      this.refs.content.value = "";
  }
}

這個(gè)代碼稍微有點(diǎn)多,但是注釋寫的非常清楚,此組件的作用就是把評(píng)論的組件寫出來。

7、在 css 目錄中新建 commentStyle.css (評(píng)論組件 css 樣式)

/*根樣式*/
.rootView{
  display: flex;
  flex-direction: column;
  background: #fff;
  padding: 10px;
  margin-top: -15px;
}
/*評(píng)論頭頭像,文本框,按鈕樣式*/
.headView{
  display: flex;
  background: #fff;
}
/*昵稱樣式*/
.nickNameStyle{
  display: flex;
  flex-direction: column;
  font-size: 12px;
}
/**
 * 評(píng)論列表樣式
 */
.commentListStyle{
  padding-left: 55px;
  margin-bottom: 10px;
  display: flex;
  align-items: flex-start;
}
/**
 * 評(píng)論內(nèi)容樣式
 */
.commentContentStyle{
  display: flex;
  flex:1;
  margin-left: 10px;
  justify-content: space-between;
}
.img{
  width: 35px;
  height: 35px;
}
/**
 * 評(píng)論內(nèi)容樣式
 */
.textareaViewStyle{
  margin-left: 20px;
  display: flex;
  flex-direction: column;
  flex:1;
  margin-bottom: 10px;
}

/**
 * 評(píng)論按鈕樣式
 */
.commentBtnStyle{
  width: 100px;
  background: #ff8146;
  margin-top: 10px;
  border: 1px solid #f77c3d;
  color: #fff;
  height: 25px;
  font-size: 14px;
}

這沒有什么好說的,經(jīng)過前面一步步的創(chuàng)建 css 這里我們大體也能看懂,注釋也非常清楚。

以上步驟我們就成功創(chuàng)建了個(gè)評(píng)論組件,但是我們要把這個(gè)組件嵌入到 WeiBoListItem.js 中并且添加事件交互,我們接著做

8、添加 CommentForm.js 到 WeiBoListItem.js 中

  • 1、首先我們?cè)?WeiBoListItem.js 中導(dǎo)入評(píng)論組件
# WeiBoListItem.js

import CommentForm from './CommentForm' ;
  • 2、在 render 的 return 方法中隱藏或顯示評(píng)論組件
# WeiBoListItem.js

  //渲染界面
  render() {

    let data = this.props.itemData ;

    return (
      <div>
          {this._renderHeadView(data)}

          <hr className={styles.hrStyle}/>

          {this._renderFooterView(data)}
          {/* 點(diǎn)擊評(píng)論按鈕 則展開評(píng)論組件,否則隱藏  新添加的方法*/}
          {this.state.isComment?  <CommentForm />:null}
        </div>
     );
  }
  • 3、給點(diǎn)贊等按鈕添加事件在 _renderFooterView() 方法中
# WeiBoListItem.js

 _renderFooterView(data){
       return(
         <div className={styles.commentViewStyle}>
           <ul className={styles.ulStyle}>
             {/* 此處新增方法 */}
             <li className={styles.liStyle} onClick={this._dianzan.bind(this)}>點(diǎn)贊:{this.state.zanNum}</li><div className={styles.shuxian}></div>
             <li className={styles.liStyle} onClick={this._comment.bind(this)}>評(píng)論:{data.NoComment}</li><div className={styles.shuxian}></div>
             <li className={styles.liStyle} onClick={this._zhuanFa.bind(this)}>轉(zhuǎn)發(fā):{data.NoPointGreat}</li>
           </ul>
         </div>
       );
   }

4、添加點(diǎn)贊等方法

# WeiBoListItem.js

   /**
    * 評(píng)論方法 
    */
   _comment(){
       this.setState({
         isComment:true
       })
     }
     /**
      * 點(diǎn)贊方法
      */
     _dianzan(){
       this.setState({
         isComment:false,
         zanNum:parseInt(this.state.zanNum)+1,
       })
     }
      /**
       * 轉(zhuǎn)發(fā)方法
       */
     _zhuanFa(){
       this.setState({
         isComment:false
       })
   }

到這里基本上我就能響應(yīng)評(píng)論組件并且輸入內(nèi)容來交互了,試一下吧。在命令行中 使用 yarn start ,并在瀏覽器輸入 localhost:8899 回車

weibo_dam.gif

我們基本上把開頭微博的樣子完成百分之九十了,接下來就是把評(píng)論組件抽取出來并且把評(píng)論列表樣式修改一下(我們這里只是把姓名,內(nèi)容,時(shí)間顯示出來,這里完全可以抽取成一個(gè)組件)

9、抽取評(píng)論列表

在 app 中新建 CommentReplyList.js (評(píng)論列表組件)

# CommentReplyList.js

import React, { Component, PropTypes } from 'react';

import styles from '../css/commentStyle.css';

/**
 * 評(píng)論列表組件
 */
export default class CommentReplyList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // 回復(fù)列表
      data:this.props.reply
    }
  }

  render() {

    let replyContent = this.state.data ;

    return (
      <div className={styles.commentListStyle}>
        <img src={require('../img/avtova.jpg')} className={styles.img} />
            {/**評(píng)論布局**/}
            <div className={styles.commentContentStyle}>
             {/**昵稱和內(nèi)容布局**/}
              <div className={styles.nickNameStyle}>
                {/**評(píng)論昵稱**/}
                <span>{replyContent.name}</span>
                {/**評(píng)論內(nèi)容**/}
                <span>{replyContent.content}</span>
              </div>
               {/**評(píng)論時(shí)間**/}
              <span className={styles.timeSize}>{replyContent.time}</span>
            </div>
      </div>
    );
  }
}

10、修改 CommentForm.js

modify_commentform.png

從圖中可以看到,我們只是修改黃色部分即可。

看一下效果:

weibo_commentlist.png

我們可以看到評(píng)論列表樣式我們修改完成了。

11、添加微博列表中圖片組件

  • 1、在 app 中新建 CommentListImgs.js (微博列表圖片組件)
import React, { Component, PropTypes } from 'react';

/**
 * 導(dǎo)入圖片樣式
 */
import styles from '../css/commentImgsStyle.css' ;
/**
 * 微博列表中的圖片 無狀態(tài)的組件
 */
export default class CommentListImgs extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    // 遍歷圖片并顯示
    var imgs = this.props.imgUrls.map(function(imgurl,index) {
    return(<li key={index} className={styles.liStyle}><img src={require('../img/avtova.jpg')} className={styles.imgStyle}></img></li>);
   });
  return(
    <ul className={styles.ulstyle}>
      {imgs}
    </ul>
  ) ;
 }
}

  • 2、添加圖片組件樣式

在 css 目錄中新建 commentImgsStyle.css 并輸入以下內(nèi)容


.imgStyle{
  width: 100px;
  height: 100px;
}
.ulstyle{
  margin-top: 0px;
  display: flex;
  flex-wrap: wrap;
  padding-left: 0px;
}
.liStyle{
  list-style:none;
  float:left;
  margin-right: 10px;
  margin-top: 10px;
  align-self: center;
}

  • 3 、修改 WeiBoListItem.js 組件 以下核心修改的地方
import CommentListImgs from './CommentListImgs.js' ;

_renderHeadView(data){
    return(
      <div className={styles.item}>
        <img src={require('../img/tiger.jpg')} className={styles.imgStyle}></img>
        <div className={styles.topRightView}>
          <div className={styles.nickNameAndSendTime}>
            <span>{data.nickName}</span>
            <span>{data.sendTime}</span>
          </div>

          <p>{data.content}</p>
            {/**新添加的內(nèi)容**/}
          {data.contentImgUrls?<CommentListImgs imgUrls={data.contentImgUrls}/>:null}
        </div>
      </div>
    )
  }

代碼太多,我們這里只貼出核心修改的地方,具體代碼看demo

我們?cè)龠\(yùn)行一下,就會(huì)看到我們開頭的效果圖

weibo-demo.gif

到此為止,我們手把手教大家擼了一個(gè)微博的小 Demo,經(jīng)過這個(gè) demo 大家掌握 webpack+yarn+react的基礎(chǔ)知識(shí),以及組件化的思想,無狀態(tài)化組件編寫等。希望大家能從 0 開始動(dòng)手寫一遍。

Demo地址

https://github.com/tigerchain/react-lesson/tree/master/lesson02/10-weibodemo

如果覺得對(duì)你有用,就點(diǎn)個(gè)喜歡吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 PS:轉(zhuǎn)載請(qǐng)注明出處作者:TigerChain地址:http...
    TigerChain閱讀 2,798評(píng)論 9 14
  • GitChat技術(shù)雜談 前言 本文較長(zhǎng),為了節(jié)省你的閱讀時(shí)間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,885評(píng)論 7 110
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,364評(píng)論 7 35
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,325評(píng)論 40 247
  • 像蟲子咬著指尖 心里隱隱作痛 指頭來回揉搓 有點(diǎn)失落 鳥兒叫 天兒明 心兒堵的慌 雨過天晴 總是難逃心里的結(jié)
    田萍閱讀 344評(píng)論 1 6

友情鏈接更多精彩內(nèi)容