React实战:留言板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/b954960630/article/details/86751555

留言板

一、展示

留言板功能:“增加留言”,“删除留言”,“修改留言”
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

二、组件设计

在这里插入图片描述
CommentBox是顶层组件,里面包含 CommentList 和 CommentForm组件;CommentList里又有若干Comment组件。


三、安装React

这里我们采用 create-react-app 快速脚手架 安装,具体安装方式请见:
React安装及目录结构(启动项目方式也在其中)


四、源码

组件:CommentBox、CommentList、Comment、CommentForm
分别对应一个js文件~

目录:
在这里插入图片描述
./src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import CommentBox from './CommentBox';
import './index.css';

let data = [
  {author:'bty',content:'悟空的自在极意功是真的厉害!!',date:'2019/2/1 下午4:00:05'},
  {author:'oppen',content:'世上只有妈妈好?爸爸呢?',date:'2019/2/1 下午3:04:05'}
];

ReactDOM.render(
	<CommentBox data={data}/>, 
	document.getElementById('root')
);

./src/CommentBox.js

import React, { Component } from 'react';
import CommentList from './CommentList';
import CommentForm from './CommentForm';

class CommentBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: this.props.data,
      editToggle: Array(this.props.data.length).fill(false),
    };
  }
  
  handleCommentSubmit(comment) {
    this.setState({
      data: this.state.data.concat([comment]),
    });
  }

  handleCommentDelete(index) {
    const data = this.state.data.slice(0),
          editToggle = this.state.editToggle.slice(0);
    data.splice(index, 1);
    editToggle.splice(index, 1);
    this.setState({
      data: data,
      editToggle: editToggle,
    }); 
  }

  handleEditToggle(index) {
        const editToggle = this.state.editToggle.slice(0);
        editToggle[index] = !editToggle[index];
        this.setState({
          editToggle: editToggle,
        });
      }

  handleCommentUpdate(index, comment) {
    const data = this.state.data.slice(0),
          editToggle = this.state.editToggle.slice(0);
    data[index] = comment;
    editToggle[index] = !editToggle[index];
    this.setState({
      data: data,
      editToggle: editToggle,
    }); 
  }

  render() {
    return (
      <div className='comment-box'>
        <h1 className='title'>评论</h1>
        <CommentList 
          {...this.state}
          handleEditToggle={(index) => this.handleEditToggle(index)}
          handleCommentDelete={(index) => this.handleCommentDelete(index)}
          handleCommentUpdate={(index, comment) => this.handleCommentUpdate(index, comment)}
        />
        <CommentForm handleCommentSubmit={(comment) => this.handleCommentSubmit(comment)}/>
      </div>
    );
  }
}

export default CommentBox;

./src/CommentList.js

import React from 'react';
import Comment from './Comment';

function CommentList(props) {
  let comments = props.data.map((item, index) => {
    item.index = index;
    return (
      <Comment 
        key={index}
        {...item}
        editToggle={props.editToggle[index]}
        handleEditToggle={() => props.handleEditToggle(index)}
        handleCommentDelete={() => props.handleCommentDelete(index)}
        handleCommentUpdate={props.handleCommentUpdate}
      />
    );
  });
  return (
    <div>{comments}</div>
  );
}

export default CommentList;

./src/Comment.js

import React, { Component } from 'react';

class Comment extends Component {
	handleSubmitUpdate(e) {
	    e.preventDefault();
	    let author = this.props.author,
	        content = this.refs.content.value,
	        date = this.props.date;
	    this.props.handleCommentUpdate(this.props.index, {author, content, date});
	}

	render() {
        let {content, author, date, editToggle} = {...this.props},
            editButton = editToggle ? '取消' : '编辑',
            contentDiv = editToggle ?
                <form className='editContent' onSubmit={(e) => this.handleSubmitUpdate(e)}>
                  <textarea defaultValue={content} ref="content"></textarea>
                  <button>完成</button>
                </form>
                    : 
                <div className='content'>{content}</div>;

        return (
	        <div className='comment'>
	            {contentDiv}
	            <div className='metadata'>
	              	<div className='author'>{author}</div>
	              	<div className='date'>{date}</div>
	              	<a className='option' href='#' onClick={this.props.handleEditToggle}>{editButton}</a>
	              	<a className='option' href='#' onClick={this.props.handleCommentDelete}>删除</a>
	            </div>
	        </div>
        );
    }
}

export default Comment;

./src/CommentForm.js

import React, { Component } from 'react';

class CommentForm extends Component {
  handleSubmit(e) {
    e.preventDefault();
    let content = this.refs.content.value,
        author = this.refs.author.value,
        date = new Date().toLocaleString(),
        warning = this.refs.warning;
    
    if(!author) {
      warning.innerHTML = '* 姓名不能为空';
      return null;
    }else if(!content) {
      warning.innerHTML = '* 评论不能为空';
      return null;
    }else {
      warning.innerHTML = '';
    }
    
    this.props.handleCommentSubmit({content, author, date});
  }

  render() {
    return (
       <form className='submitform' onSubmit={(e) => this.handleSubmit(e)}>
        <span className='warning' ref='warning'></span>
        <div className='form-row'>
          <input type="text" placeholder='姓名' ref='author'/>
        </div>
        <div className='form-row'>
          <textarea placeholder='评论' ref='content'></textarea>
        </div>
        <div className='form-row'>
          <button>发表</button>
        </div>
      </form>
    );
  }
}

export default CommentForm;

./src/index.css:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-size: 12px;
}
a {
  text-decoration: none;
}
.comment-box {
  width: 80%;
  border: 1px solid #ccc;
  border-radius: 3px;
  margin: 15px;
  padding: 30px;
}
.title,
.comment,
.metadata,
.submitform {
  width: 100%;
}

.title {
  border-bottom: 1px solid #ccc; 
  padding-bottom: 10px;
  color: #B8860B;
  font-size: 16px;
}
.comment {
  background: #F8F8FF;
  margin-top: 20px;
  padding: 20px 20px 14px 20px;
}
.comment .content {
  width: 100%;
  font-size: 15px;
  color: #333;
}
.metadata{
  margin-top: 10px;
}
.metadata .author,
.metadata .date,
.metadata .option{
  display: inline-block;
  color: #A9A9A9;
}
.metadata .author,
.metadata .date {
  margin-right: 30px;
}
.metadata .option {
  margin-right: 6px;
}
.metadata .option:hover{
  text-decoration: underline;
}
.submitform {
  margin-top: 20px;
}
.editContent textarea{
  width:88%;
  min-height: 50px;
  border-radius: 3px;
  border: 1px solid #ccc;
  padding: 5px 10px;

}
.editContent button {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid #97CBFF;
  background: #97CBFF;
  color: #fff;
  position: relative;
  left: 20px;
  top:-19px;
}
.editContent button:hover{
  cursor: pointer;
  background: #FF5151;
  border: 1px solid #FF5151;
}

.warning {
  color: red;
}
.form-row {
  padding: 10px 0;
}
.form-row input[type='text'],
.form-row button,
.form-row textarea {
  border-radius: 2px;
}
.form-row input[type='text'],
.form-row textarea {
  width: 50%;
  border: 1px solid #ccc;
  padding: 8px 10px;
}
.form-row textarea {
  min-height: 100px;
}
.form-row button {
  padding: 6px;
  width: 80px;
  background: #97CBFF;
  border: 1px solid #97CBFF;
  color: #fff;
  font-size: 13px;
}
.form-row button:hover {
  cursor: pointer;
}

猜你喜欢

转载自blog.csdn.net/b954960630/article/details/86751555