React 小案例 使用者評論

Winter_Wang發表於2019-01-19

功能展示 :

1.使用者可輸入使用者名稱

2.輸入評論內容

3.點選發布

4.使用者名稱和使用者評論會被顯示在列表裡,第一個評論在最上面

5.且顯示本條評論離現在過去了多長時間

6.滑鼠放在事件上方可顯示刪除鍵,點選刪除,刪除當前

React 小案例 使用者評論

總體結構:

1.components下建立comment資料夾

2.先建立使用者輸入元件:CommentInput

3.再建立單條使用者評論檢視:Comment

4.接著建立CommentList元件,將使用者評論遍歷渲染成評論列表

5.建立CommentApp元件,將CommentInput評論元件和CommentList列表元件渲染到一起

6.再index.js中引入展示

React 小案例 使用者評論

使用者輸入元件:CommentInput 所有內容

1.建立使用者名稱輸入檢視模板,

用ref獲取input此DOM節點的值,

import {Component} from "react";
import React from "react";


class CommentInput extends Component{
    constructor(){
        super();
        this.state={
            //使用者名稱
            username:'',
            //評論內容
            content:''
        }
    }

//監聽使用者輸入使用者名稱事件
    handleUsernameChange=(event)=>{
        this.setState({
            username:event.target.value
        })
    };
//監聽使用者輸入評論事件
    handleContentChange=(event)=>{
        this.setState({
            content:event.target.value
        })
    };
    //點選發布事件
    handleSubmit=()=>{
        if(this.props.submit){
            this.props.submit({
                username:this.state.username,
                content:this.state.content,
                createTime:+new Date()
            })
        }
        //點選發布後將state中的評論區域重新至為空
        this.setState({
            content:''
        })
    };
//使用者名稱框失去焦點
    handleUsernameHold=(event)=>{
        //將使用者名稱資料儲存到本地
        localStorage.setItem('username',event.target.value)
    };
    //將要裝載,在render之前呼叫;
    componentWillMount(){
        //改變資料重新渲染前get獲取使用者名稱
        const username=localStorage.getItem('username');
        if(username){
            this.setState({username})
        }
    }
    //(裝載完成),在render之後呼叫
    componentDidMount(){
        //使用者重新整理之後,使用者名稱輸入自動獲取焦點
        this.input.focus();
    };

    render(){
        return(
            <div className='comment-input'>
                <div className='comment-field'>
                    <span className='comment-field-name'>使用者名稱:</span>
                    <div className='comment-field-input'>
                        <input
                            ref={(input)=>this.input=input}
                            value={this.state.username}
                            onBlur={this.handleUsernameHold}
                            onChange={this.handleUsernameChange}
                        />
                    </div>
                </div>
                <div className='comment-field'>
                    <span className='comment-field-name'>評論內容:</span>
                    <div className='comment-field-input'>
                        <textarea
                            value={this.state.content}
                            onChange={this.handleContentChange}
                        />
                    </div>
                </div>
                <div className='comment-field-button'>
                    <button onClick={this.handleSubmit}>
                        釋出
                    </button>
                </div>
            </div>
        )
    }
}
export default CommentInput//給input標籤繫結 ref={(input)=>{this.input = input}}
//用來直接獲取dom節點的值,此處將input的值賦給this.input,讓外部能訪問

複製程式碼


單條使用者評論檢視:Comment 所有內容

import {Component} from "react";
import React from "react";

class Comment extends Component{
    constructor(){
        super();
        this.state ={
            //初始化時間
            timeString:''
        }
    }

    //顯示使用者評論時間
    handleTimeString=()=>{
        const item=this.props.item;
        //當前時間減去使用者建立時的時間
        const duration=(+Date.now()-item.createTime)/1000;
        //如果足夠60就轉成分,不夠60就轉成秒
        return duration>60?`${Math.round(duration/60)}分鐘前`:`${Math.round(Math.max(duration,1))}秒前`;
    };

    //點選刪除事件
    //將handleDelete事件傳出,index傳出
    handleDelete=()=>{
        if(this.props.deleteItem){
            this.props.deleteItem(this.props.index)
        }
    };

    render(){
        return(
            <div className='comment'>
                <div className='comment-user'>
                    <span className='comment-username'>{this.props.item.username} </span>:
                </div>
                <p>{this.props.item.content}</p>
                <span className="comment-delete" onClick={this.handleDelete}>刪除</span>
                <span className="comment-createdtime">
                    {this.handleTimeString()}
                </span>
            </div>
        )
    }
}

export default Comment複製程式碼


評論列表 CommentList 所有內容

import {Component} from "react";
import React from "react";
import Comment from './Comment'

class CommentList extends Component{

    constructor(){
        super();
        this.state ={
            items:[]
        }
    }
//將陣列列表傳出,將deleteItem刪除事件傳出
    render(){
        return(
            <div>
                {this.props.items.map((item,index)=>
                    <Comment deleteItem={this.props.deleteItem}
                             item={item} index={index} key={index}
                    />)}
            </div>
        )
    }
}

export default CommentList複製程式碼


總元件CommentApp 的所有內容

import {Component} from "react";
import React from "react";
import CommentInput from './CommentInput'
import CommentList from './CommentList'


class CommentApp extends Component{
    constructor(){
        super();
        this.state ={
            items:[]
        }
    }
    //點選傳送
    handleSubmit=(item)=>{
        //點選傳送時push當前那條
        this.state.items.push(item);
        //更新資料列表
        this.setState({
            items:this.state.items
        });
        //使用者重新整理時儲存當前資料
        localStorage.setItem('items',JSON.stringify(this.state.items))
    };
    //刪除事件
    handleDelete=(index)=>{
        console.log(index);
        //點選刪除,刪除當前
        this.state.items.splice(index,1);
        //列表資料更新至最新
        this.setState({
            items:this.state.items
        });
        //刪除後儲存當下資料
        localStorage.setItem('items',JSON.stringify(this.state.items))
    };
    //裝載前獲取
    componentWillMount(){
        let items=localStorage.getItem('items');
        if(items){
            items=JSON.parse(items);
            this.setState({items})
        }
    };

    render(){
        return(
            <div className="wrapper">
                <CommentInput submit={this.handleSubmit} />
                <CommentList deleteItem={this.handleDelete} items={this.state.items}/>
            </div>
        )
    }
}

export default CommentApp

// window.localStorage
// 儲存資料語法:
// localStorage.setItem("key", "value");
// 讀取資料語法:
// var lastname = localStorage.getItem("key");
// 刪除資料語法:
// localStorage.removeItem("key");複製程式碼


index.js下所有內容:

import React from 'react';
import ReactDOM from 'react-dom';
import CommentApp from "./components/comment/CommentApp";
import './index.css'


ReactDOM.render(<CommentApp/>, document.getElementById('root'));

複製程式碼

index.css下所有樣式內容:

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background-color: #fbfbfb;
}

.wrapper {
  width: 500px;
  margin: 10px auto;
  font-size: 14px;
  background-color: #fff;
  border: 1px solid #f1f1f1;
  padding: 20px;
}

/* 評論框樣式 */
.comment-input {
  background-color: #fff;
  border: 1px solid #f1f1f1;
  padding: 20px;
  margin-bottom: 10px;
}

.comment-field {
  margin-bottom: 15px;
  display: flex;
}

.comment-field .comment-field-name {
  display: flex;
  flex-basis: 100px;
  font-size: 14px;
}

.comment-field .comment-field-input {
  display: flex;
  flex: 1;
}

.comment-field-input input,
.comment-field-input textarea {
  border: 1px solid #e6e6e6;
  border-radius: 3px;
  padding: 5px;
  outline: none;
  font-size: 14px;
  resize: none;
  flex: 1;
}

.comment-field-input textarea {
  height: 100px;
}

.comment-field-button {
  display: flex;
  justify-content: flex-end;
}

.comment-field-button button {
  padding: 5px 10px;
  width: 80px;
  border: none;
  border-radius: 3px;
  background-color: #00a3cf;
  color: #fff;
  outline: none;
  cursor: pointer;
}

.comment-field-button button:active {
  background: #13c1f1;
}

/* 評論列表樣式 */
.comment-list {
  background-color: #fff;
  border: 1px solid #f1f1f1;
  padding: 20px;
}

/* 評論元件樣式 */
.comment {
  position: relative;
  display: flex;
  border-bottom: 1px solid #f1f1f1;
  margin-bottom: 10px;
  padding-bottom: 10px;
  min-height: 50px;
}

.comment .comment-user {
  flex-shrink: 0;
}

.comment-username {
  color: #00a3cf;
  font-style: italic;
}

.comment-createdtime {
  padding-right: 5px;
  position: absolute;
  bottom: 0;
  right: 0;
  padding: 5px;
  font-size: 12px;
}

.comment:hover .comment-delete {
  color: #00a3cf;
}

.comment-delete {
  position: absolute;
  right: 0;
  top: 0;
  color: transparent;
  font-size: 12px;
  cursor: pointer;
}

.comment p {
  margin: 0;
  /*text-indent: 2em;*/
}

code {
  border: 1px solid #ccc;
  background: #f9f9f9;
  padding: 0px 2px;
}複製程式碼


相關文章